使用泛型验证器验证值



我有一个继承自AbstractValidator<T>的类实现

让事情变得简单:假设我有

public class Users{
[Required]
public string Name {get;set;}
} 

我要做的是调用

RuleFor(x => x.Name).NotEmpty();

但是属性将在运行时被知道,所以我想用反射和表达式树来做到这一点。

我没有调用RuleFor方法,下面是我的实现和注释部分是我尝试过的事情。如有任何帮助,不胜感激。

GenValidator<T> : AbstractValidator<T> 
{
// constructor etc..
public async Task<IEnumerable<string>> ValidateValueAsync(T model, string propertyName) 
{
try
{
var loType = model.GetType();
var property = loType.GetProperty(propertyName);
var param = Expression.Parameter(loType);
var propertyExpression = Expression.Property(param, property);
var lambdaExpressionType = typeof(Expression);

var lambda = Expression.Lambda(typeof(Func<,>).MakeGenericType(model.GetType(), typeof(object)), propertyExpression, param);


var lambdaMethod = typeof(Expression).GetMethod("Lambda", new Type[] { typeof(Type), typeof(Expression), typeof(ParameterExpression[]) });
var lambda2 = lambdaMethod.MakeGenericMethod(loType, typeof(object)).Invoke(null, new object[] { propertyExpression, new ParameterExpression[] { param } });
var compileMethod = lambda.GetType().GetMethod("Compile");
var func = compileMethod.Invoke(lambda2, null);
var ruleForMethod = typeof(AbstractValidator<T>).GetMethod("RuleFor");
var genericRuleForMethod = ruleForMethod.MakeGenericMethod(loType);
genericRuleForMethod.Invoke(this, new object[] { func });

//RuleFor<object>(lambda).NotEmpty().WithMessage("The property is required.");
//RuleFor(lambda.Compile()).NotEmpty().WithMessage("The property is required.");



}
catch (Exception ex)
{

}
//var lambda = Expression.Lambda<Func<T, object>>(property, param);
//RuleFor(lambda).NotEmpty().WithMessage("The property is required.");

var valContext = ValidationContext<T>.CreateWithOptions(model, x => x.IncludeProperties(_propertyName));

var result = await ValidateAsync(valContext);

if (result.IsValid)
{
return Array.Empty<string>();
}
return result.Errors.Select(e => e.ErrorMessage);
}
}

编辑

public class MyValidator
{
public MyValidator(string propertyname)
{
// this is how you call using fluentvalidation but it's hardcoded.
RuleFor(x => x.Name).NotEmpty();
// I do know want to hard code.
//I want to do some magical stuff at this point 
//and invoke the RuleFor method, I only have propertyname as a 
//string, type of model and model at this point

}
}

EDIT2

private void GenericRuleFor(T Model, string propertyName)
{
var property = Model.GetType().GetProperty(propertyName);
var param = Expression.Parameter(Model.GetType());
var propertyExpression = Expression.Property(param, property);
var lambda = Expression.Lambda(typeof(Func<,>).MakeGenericType(Model.GetType(), property.PropertyType), propertyExpression, param);
var abstractValidatorType = typeof(AbstractValidator<>).MakeGenericType(Model.GetType());
var ruleForMethod = abstractValidatorType.GetMethods().First(m => m.Name == "RuleFor" && m.IsGenericMethodDefinition);
var genericRuleForMethod = ruleForMethod.MakeGenericMethod(property.PropertyType);
genericRuleForMethod.Invoke(this, new object[] { lambda });
}

这是我的代码的修改版本,仍然不能工作。当我调用genericRuleForMethod时,它抛出一个异常告诉我对象类型与目标类型不匹配

下面是我的GenericRuleFor工作版本。主要的区别似乎是你试图从typeof(AbstractValidator<>)中获得RuleFor方法,我只是从this.GetType()中获得它

private void GenericRuleFor(string propertyName)
{
var type = typeof(T);
var property = type.GetProperty(propertyName);
var param = Expression.Parameter(type);
var propertyExpression = Expression.Property(param, property);
var lambda = Expression.Lambda(typeof(Func<, >).MakeGenericType(type, property.PropertyType), propertyExpression, param);
var thisType = this.GetType();
var ruleForMethod = thisType.GetMethod("RuleFor", BindingFlags.Public | BindingFlags.Instance);
var genericRuleForMethod = ruleForMethod.MakeGenericMethod(property.PropertyType);
// result is used by extension method
var result = genericRuleForMethod.Invoke(this, new object[]{lambda});
//NotEmpty method is an Extension metot which is contained by DefaultValidatorExtensions
var extensionsType = typeof(DefaultValidatorExtensions);
var notEmptyMethod = extensionsType.GetMethod("NotEmpty", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(type, property.PropertyType);
notEmptyMethod.Invoke(null, new object[]{result});
}

小提琴来了

最新更新