代码之家  ›  专栏  ›  技术社区  ›  MistyK

泛型参数的协方差与基于参数类型的约定

  •  0
  • MistyK  · 技术社区  · 6 年前

    我真的很难为FluentValidator创建基于接口/约定的规则。它有以下几类

       abstract class AbstractValidator<T>
        {
    
        IRuleBuilderInitial<T, TProperty> RuleFor<TProperty>(Expression<Func<T, TProperty>> expression)
        ...
        }
    
    
    public interface IWithPropertyA
    {
      string PropertyA{get;set;}
    }
    
    public interface IWithPropertyB
    {
     string PropertyB{get;set;}
    }
    
    public class Handler1Data: IWithPropertyA
    {
     public string PropertyA {get;set;}
    }
    public class Handler2Data: IWithPropertyA, IWithPropertyB
    {
     public string PropertyA {get;set;}
     public string PropertyB {get;set;}
    }
    
    public class Handler1 : AbstractValidator<Handler1Data> {}
    public class Handler2 : AbstractValidator<Handler2Data> {}
    

    我正在尝试创建扩展方法,它基本上会检查泛型参数是否实现了特定接口,然后向其添加规则:

    public static void ValidateAll<T>(this AbstractValidator<T> validator)
            {
    
               (validator as AbstractValidator<IWithPropertyA>)?.RuleFor(x => x.PropertyA).NotEmpty().WithMessage("PropertyA Missing");
               (validator as AbstractValidator<IWithPropertyB>)?.RuleFor(x => x.PropertyB).NotEmpty().WithMessage("PropertyB Missing");
            }
    

    AbstractValidator<PropertyA> 也不是 AbstractValidator<PropertyB> . 我试着创建我自己的基本验证器,如下面所示,然后在此基础上创建扩展方法,但我做不到。

    public interface IMyValidator<in T>
    {
       void AddMyRule<TProperty>(Expression<Func<T, TProperty>> expression) //it doesn't work because Expression<Func<T,Property> cannont be covariant
    }
    
    public abstract class MyBaseValidator<T>: AbstractValidator<T> ,IMyValidator<T>
    {
       void AddMyRule<TProperty>(Expression<Func<T, TProperty>> expression)
    }
    

    方法将在每个处理程序中调用,如下所示:

    public class Handler1 : AbstractValidator<Handler1Data> {
      this.ValidateAll();
    }
    
    2 回复  |  直到 6 年前
        1
  •  0
  •   Toni Petrina    6 年前

    你不是想写:

    (validator as AbstractValidator<IWithPropertyA>)
        ?.RuleFor(x => x.PropertyA)
         .NotEmpty()
         .WithMessage("Property1 Missing");
    

    因为 Property1 在任何地方都没有定义。

        2
  •  0
  •   MistyK    6 年前

     public interface IMyValidator<out T>
        {
            void AddMyRule<TProperty>(Func<T, TProperty> expression, string message);
        }
    
        public abstract class MyBaseValidator<T> : AbstractValidator<T>, IMyValidator<T>
            {
                public void AddMyRule<TProperty>(Func<T, TProperty> expression, string message)
                {
                    var exp = FuncToExpression(expression);
                    RuleFor(exp).NotEmpty().WithMessage(message);
                }
    
                private static Expression<Func<T, P>> FuncToExpression<T, P>(Func<T, P> f) => x => f(x);
            }
    
    public static class Ext
        {
            public static void ValidateAll<T>(this AbstractValidator<T> validator)
            {
                (validator as IMyValidator<IWithPropertyA>)?.AddMyRule(x => x.PropertyA, "PropA Cant be empty");
                (validator as IMyValidator<IWithPropertyB>)?.AddMyRule(x => x.PropertyB, "PropB Cant be empty");
            }
        }
    
     public class Handler1 : MyBaseValidator<Handler1Data>
        {
            public Handler1()
            {
                this.ValidateAll();
            }
        }
        public class Handler2 : MyBaseValidator<Handler2Data> { }