我有一个具有2个方法的类:
MaxLength(string text, int maxLength, string propName, string message = null);
MinValue(int value, int min, string propName, string message = null);
由于用户可以通过传入每个值来使用它。当他们想验证类时,我想使其变得更简单,更像是自动映射器。例如
public class MyModel {
public string Category { get; set; }
public int Number { get; set; }
}
目前他们必须写
MyModel model = //comes from API call or where ever
var validator = new Validator();
validator.MaxLength(model.Category, 4, "Category");
validator.MinValue(model.Number , 3, "Number ");
我想要实现的是能够为该类设置映射:
public class Profile1 : ClassValidationProfile
{
public Profile1()
{
CreateMap<Model1>()
.ForMember(x => x.Category, m => m.MaxLength(4))
.ForMember(x => x.Number , m => m.MinValue(3));
}
}
因此基于自动映射器,我有:
IMappingExpression<T> ForMember<TMember>(Expression<Func<T, TMember>> member, Action<IValidatorExpression> memberAction)
但是,这将允许我设置.ForMember(x => x.Name, m => m.MinValue(18))
,这是错误的,并且在运行时会出错。
我希望能够将操作memberAction
限制为其正确的类型(字符串对字符串,整数对整数等)。因此,当用户设置其映射时,它知道哪些操作方法对于表达式第一部分中给出的属性类型有效。
然后可以使用此信息为每个属性生成有效的验证器方法。
答案 0 :(得分:2)
您应该使用Action<IValidatorExpression>
来代替TMember
来保留类型-例如Func<TMember, bool>
(该函数将成员值作为输入并返回一个布尔值,指示是否通过了验证。)
我尝试构建一些示例程序,最终验证如下所示:
var validator = Validator<MyModel>.Create()
.ForMember(x => x.Category, cat => cat == "A")
.ForMember(x => x.Number, num => num < 200);
MyModel model = new MyModel {
Category = "A",
Number = 100,
};
validator.Validate(model);
这是您要找的吗?
以下是实现上述目标的代码:
class Validator<TClass> {
private List<IObjectValidator<TClass>> _constraints = new List<IObjectValidator<TClass>>();
public static Validator<TClass> Create() {
return new Validator<TClass>();
}
public Validator<TClass> ForMember<TMember>(Expression<Func<TClass, TMember>> memberSelectorExpression, Func<TMember, bool> memberValidation, string errorMessage = null) {
_constraints.Add(new ObjectValidator<TClass, TMember>(memberSelectorExpression.Compile(), memberValidation, errorMessage ?? memberSelectorExpression.ToString() + " did not pass validation"));
return this;
}
public void Validate(TClass obj) {
foreach (var constraint in _constraints) {
if (!constraint.Validate(obj))
throw new Exception(constraint.ErrorMessage);
}
}
}
interface IObjectValidator<T> {
bool Validate(T obj);
string ErrorMessage { get; }
}
class ObjectValidator<T, TMember> : IObjectValidator<T>
{
private Func<T, TMember> _memberSelector;
private Func<TMember, bool> _memberValidation;
public string ErrorMessage { get; }
public ObjectValidator(Func<T, TMember> memberSelector, Func<TMember, bool> memberValidation, string errorMessage) {
_memberSelector = memberSelector;
_memberValidation = memberValidation;
ErrorMessage = errorMessage;
}
public bool Validate(T obj)
{
return _memberValidation.Invoke(_memberSelector.Invoke(obj));
}
}