如何在 FluentValidation 中使用反射?
How to use Reflection in FluentValidation?
我有一个场景,我想在其中使用反射来使用 FluentValidation 进行验证。像这样:
public class FooValidator : AbstractValidator<Foo>
{
public FooValidator(Foo obj)
{
// Iterate properties using reflection
var properties = ReflectionHelper.GetShallowPropertiesInfo(obj);
foreach (var prop in properties)
{
// Create rule for each property, based on some data coming from other service...
//RuleFor(o => o.Description).NotEmpty().When(o => // this works fine when foo.Description is null
RuleFor(o => o.GetType().GetProperty(prop.Name)).NotEmpty().When(o =>
{
return true; // do other stuff...
});
}
}
}
调用 ReflectionHelper.GetShallowPropertiesInfo(obj)
returns 对象的“浅层”属性。然后,我为每个 属性 创建一个规则。
这是我获取对象属性的代码:
public static class ReflectionHelper
{
public static IEnumerable<PropertyInfo> GetShallowPropertiesInfo<T>(T o) where T : class
{
var type = typeof(T);
var properties =
from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where pi.PropertyType.Module.ScopeName == "CommonLanguageRuntimeLibrary"
&& !(pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
select pi;
return properties;
}
}
这段代码可以编译执行
IValidator<Foo> validator = new FooValidator(foo);
var results = validator.Validate(foo);
但它不能正常工作(验证永远不会失败)。有什么办法可以实现吗?
注意:演示代码可以在 FluentValidationReflection
找到 int Github
我终于找到了有效的解决方案。我创建了一个接收 PropertyInfo 参数的自定义 PropertyValidator:
public class CustomNotEmpty<T> : PropertyValidator
{
private PropertyInfo _propertyInfo;
public CustomNotEmpty(PropertyInfo propertyInfo)
: base(string.Format("{0} is required", propertyInfo.Name))
{
_propertyInfo = propertyInfo;
}
protected override bool IsValid(PropertyValidatorContext context)
{
return !IsNullOrEmpty(_propertyInfo, (T)context.Instance);
}
private bool IsNullOrEmpty(PropertyInfo property, T obj)
{
var t = property.PropertyType;
var v = property.GetValue(obj);
// Omitted for clarity...
}
}
以及IRuleBuilder
的扩展方法:
public static class ValidatorExtensions
{
public static IRuleBuilderOptions<T, T> CustomNotEmpty<T>(
this IRuleBuilder<T, T> ruleBuilder, PropertyInfo propertyInfo)
{
return ruleBuilder.SetValidator(new CustomNotEmpty<T>(propertyInfo));
}
}
有了这个我可以改变我的 FooValidator
如下:
public class FooValidator : AbstractValidator<Foo>
{
public FooValidator(Foo obj)
{
// Iterate properties using reflection
var properties = ReflectionHelper.GetShallowPropertiesInfo(obj);
foreach (var prop in properties)
{
// Create rule for each property, based on some data coming from other service...
RuleFor(o => o)
.CustomNotEmpty(obj.GetType().GetProperty(prop.Name))
.When(o =>
{
return true; // do other stuff...
});
}
}
}
现在我可以使用反射为特定属性添加规则
我有一个场景,我想在其中使用反射来使用 FluentValidation 进行验证。像这样:
public class FooValidator : AbstractValidator<Foo>
{
public FooValidator(Foo obj)
{
// Iterate properties using reflection
var properties = ReflectionHelper.GetShallowPropertiesInfo(obj);
foreach (var prop in properties)
{
// Create rule for each property, based on some data coming from other service...
//RuleFor(o => o.Description).NotEmpty().When(o => // this works fine when foo.Description is null
RuleFor(o => o.GetType().GetProperty(prop.Name)).NotEmpty().When(o =>
{
return true; // do other stuff...
});
}
}
}
调用 ReflectionHelper.GetShallowPropertiesInfo(obj)
returns 对象的“浅层”属性。然后,我为每个 属性 创建一个规则。
这是我获取对象属性的代码:
public static class ReflectionHelper
{
public static IEnumerable<PropertyInfo> GetShallowPropertiesInfo<T>(T o) where T : class
{
var type = typeof(T);
var properties =
from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where pi.PropertyType.Module.ScopeName == "CommonLanguageRuntimeLibrary"
&& !(pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
select pi;
return properties;
}
}
这段代码可以编译执行
IValidator<Foo> validator = new FooValidator(foo);
var results = validator.Validate(foo);
但它不能正常工作(验证永远不会失败)。有什么办法可以实现吗?
注意:演示代码可以在 FluentValidationReflection
找到 int Github我终于找到了有效的解决方案。我创建了一个接收 PropertyInfo 参数的自定义 PropertyValidator:
public class CustomNotEmpty<T> : PropertyValidator
{
private PropertyInfo _propertyInfo;
public CustomNotEmpty(PropertyInfo propertyInfo)
: base(string.Format("{0} is required", propertyInfo.Name))
{
_propertyInfo = propertyInfo;
}
protected override bool IsValid(PropertyValidatorContext context)
{
return !IsNullOrEmpty(_propertyInfo, (T)context.Instance);
}
private bool IsNullOrEmpty(PropertyInfo property, T obj)
{
var t = property.PropertyType;
var v = property.GetValue(obj);
// Omitted for clarity...
}
}
以及IRuleBuilder
的扩展方法:
public static class ValidatorExtensions
{
public static IRuleBuilderOptions<T, T> CustomNotEmpty<T>(
this IRuleBuilder<T, T> ruleBuilder, PropertyInfo propertyInfo)
{
return ruleBuilder.SetValidator(new CustomNotEmpty<T>(propertyInfo));
}
}
有了这个我可以改变我的 FooValidator
如下:
public class FooValidator : AbstractValidator<Foo>
{
public FooValidator(Foo obj)
{
// Iterate properties using reflection
var properties = ReflectionHelper.GetShallowPropertiesInfo(obj);
foreach (var prop in properties)
{
// Create rule for each property, based on some data coming from other service...
RuleFor(o => o)
.CustomNotEmpty(obj.GetType().GetProperty(prop.Name))
.When(o =>
{
return true; // do other stuff...
});
}
}
}
现在我可以使用反射为特定属性添加规则