【问题标题】:How to use Reflection in FluentValidation?如何在 FluentValidation 中使用反射?
【发布时间】:2016-06-22 15:44:47
【问题描述】:

我有一个场景,我想通过 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) 的调用返回对象的“浅”属性。然后,我为每个属性创建一个规则。 这是我获取对象属性的代码:

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);

但它不能正常工作(验证永远不会失败)。有什么方法可以实现吗?

注意:演示代码可以在 Github FluentValidationReflection找到

【问题讨论】:

    标签: c# .net validation reflection fluentvalidation


    【解决方案1】:

    我终于找到了一个可行的解决方案。我创建了一个接收 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...
                });
            }
        }
    }
    

    现在我可以使用反射为特定属性添加规则

    【讨论】:

      猜你喜欢
      • 2021-10-16
      • 2021-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多