通用参数中的协变和基于参数类型的约定
Covariance in generic parameter and convention based on parameter type
我真的很难为 FluentValidator 创建基于 interface/convention 的规则。它具有以下 class
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 不是协变的,因此验证器不能转换为 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();
}
你不是想写:
(validator as AbstractValidator<IWithPropertyA>)
?.RuleFor(x => x.PropertyA)
.NotEmpty()
.WithMessage("Property1 Missing");
因为Property1
没有在任何地方定义。
我找到了一种避免使用表达式的解决方法,这显然是这里的问题。它的缺点是我们丢失了 属性 名称,我们必须手动配置消息。
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> { }
我真的很难为 FluentValidator 创建基于 interface/convention 的规则。它具有以下 class
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 不是协变的,因此验证器不能转换为 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();
}
你不是想写:
(validator as AbstractValidator<IWithPropertyA>)
?.RuleFor(x => x.PropertyA)
.NotEmpty()
.WithMessage("Property1 Missing");
因为Property1
没有在任何地方定义。
我找到了一种避免使用表达式的解决方法,这显然是这里的问题。它的缺点是我们丢失了 属性 名称,我们必须手动配置消息。
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> { }