簡潔版本
如何強制BaseClass的TModel泛型引數與派生自它的類的型別相同?
public class BaseClass<TModel, TValidator> where TValidator : IValidator<TModel> { }
public class Person : BaseClass<Person, PersonValidator> { }
在這個例子中,我如何強制BaseClass'sTModel是型別Person而不是別的東西?
這是無效的語法,但這是我的想象:
public class BaseClass<TValidator> where TValidator : IValidator<this> { }
public class Person : BaseClass<PersonValidator> { }
這是可能的還是我應該使用完全不同的解決方案來實作這一點?
長版
我正在嘗試將一些驗證邏輯提取到基類中,但我不知道如何約束泛型型別,因此生成的基類完全是萬無一失的。
這是一個沒有基類的所有驗證邏輯的示例。我正在使用 FluentValidation 驗證物件,并通過IDataErrorInfo介面公開該驗證結果,以便 WPF UI 可以使用它。
原始解決方案
public class User : IDataErrorInfo
{
private readonly IValidator<Person> _validator = new();
public string Username { get; set; }
public string Password { get; set; }
private string ValidateAndGetErrorForProperty(string propertyName)
{
var result = _validator.Validate(this);
if (result.IsValid)
{
return string.Empty;
}
return result.Errors.FirstOrDefault(a => a.PropertyName == propertyName)?.ErrorMessage ?? string.Empty;
}
//IDataErrorInfo implementation
public string Error => string.Empty;
public string this[string columnName] => ValidateAndGetErrorForProperty(columnName);
}
public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
RuleFor(a => a.Username)
.EmailAddress();
RuleFor(a => a.Password)
.MinimumLength(12);
}
}
驗證實作分離為一個基類
我想將驗證邏輯和IDataErrorInfo實作分離到一個基類中,這樣就不必在每個模型類中重復這個樣板。這就是我所擁有的。
public abstract class ValidationBase<TModel, TValidator> : IDataErrorInfo where TValidator : IValidator<TModel>, new()
{
private readonly TValidator _validator;
public ValidationBase()
{
_validator = Activator.CreateInstance<TValidator>();
}
private string ValidateAndGetErrorForProperty(string propertyName)
{
//I have to check if this is of type TModel since the TModel isn't constraint to this
if (this is not TModel model)
{
throw new InvalidOperationException($"Instance is not of the supported type: {typeof(TModel)}. Type of {GetType()} found instead");
}
var result = _validator.Validate(model);
if (result.IsValid)
{
return string.Empty;
}
return result.Errors.FirstOrDefault(a => a.PropertyName == propertyName)?.ErrorMessage ?? string.Empty;
}
//IDataErrorInfo implementation
public string Error => string.Empty;
public string this[string columnName] => ValidateAndGetErrorForProperty(columnName);
}
這是我使用它的方式:
public class User : ValidationBase<User, UserValidator>
{
public string Username { get; set; }
public string Password { get; set; }
}
問題
我對這個解決方案的問題是你可以撰寫這個無效的代碼:
public class InvalidClass : ValidationBase<User, UserValidator>
{
}
uj5u.com熱心網友回復:
這是你想要的?
public interface IValidator<TModel>
{
}
public class BaseClass<TModel, TValidator>
where TModel : BaseClass<TModel, TValidator>
where TValidator
: IValidator<TModel> { }
// Only classes derived from BaseClass can be instantiated
public class Person
: BaseClass<Person, PersonValidator> { }
public class PersonValidator
: IValidator<Person>
{
}
這是一個經典模式,其中泛型引數被限制在派生類中。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/477879.html
上一篇:python常用標準庫(math數學模塊和random隨機模塊)
下一篇:C#泛型邊界
