.net 如何在FluentValidation中使用反射?

oiopk7p5  于 2023-01-10  发布在  .NET
关注(0)|答案(2)|浏览(155)

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

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处找到

yptwkmov

yptwkmov1#

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

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

5t7ly7z5

5t7ly7z52#

为了反思我用
(x =〉新对象().获取类型().获取属性(x.过滤器.列名)).非空();

相关问题