C# 抑制基类属性验证以支持派生类重写的属性验证
我使用C# 抑制基类属性验证以支持派生类重写的属性验证,c#,asp.net-core,fluentvalidation,C#,Asp.net Core,Fluentvalidation,我使用Fluent validation库验证来自webApi的传入请求,并使用以下模型结构进行验证: public class BaseClass { public MyEnum MyProperty { get; set; } } public class DerivedClass : BaseClass { public new string MyProperty { get; set; } } 请注意DerivedClass.MyPropertyproperty的ne
Fluent validation
库验证来自webApi
的传入请求,并使用以下模型结构进行验证:
public class BaseClass
{
public MyEnum MyProperty { get; set; }
}
public class DerivedClass : BaseClass
{
public new string MyProperty { get; set; }
}
请注意DerivedClass.MyProperty
property的new
关键字。以下是我的fluent验证实现:
public class BaseClassValidator<T> : AbstractValidator<T> where T : BaseClass
{
public BaseClassValidator()
{
RuleFor(prop => prop.MyProperty).IsInEnum();
}
}
public class DerivedClassValidator<T> : BaseClassValidator<DerivedClass>
{
public DerivedClassValidator()
{
RuleFor(prop => prop.MyProperty).NotEmpty();
}
}
公共类BaseClassValidator:AbstractValidator,其中T:BaseClass
{
公共BaseClassValidator()
{
RuleFor(prop=>prop.MyProperty.IsInEnum();
}
}
公共类DerivedClassValidator:BaseClassValidator
{
公共派生类验证器()
{
RuleFor(prop=>prop.MyProperty).NotEmpty();
}
}
要验证的输入模型类型为DerivedClass
不过,我还有几个其他属性,为了进一步澄清,我将它们切掉。
问题是,
FluentValidator
调用BaseClass
和DerivedClass
的验证,而所需的行为是,当使用new
关键字覆盖属性时,仅验证DerivedClass
的属性,并保留同名的BaseClass
属性未选中。问题是:是否有任何内置功能支持此场景“抑制在
DerivedClass
中重写的BaseClass
属性的验证,而是使用相应的DerivedClass
对这些属性的验证”底部的代码片段仍然有点奇怪。“RuleFor”不知从何而来,没有显示它基于什么输入
通常,您会使用继承来重写属性的getter和setter,这样无论您获取它的基类还是派生类,都会由派生类设置该属性。new
键用于覆盖对该特定级别上给定成员的访问,这意味着如果您处理的是派生类,则无法再直接访问隐藏成员。但您可以简单地将其强制转换为基类,然后无论如何都这样做
您还将验证放入构造函数中。派生类必须调用其基类的现有构造函数(如果未定义任何构造函数,则它是一个公共的、无参数的空构造函数)。这意味着无论何时创建派生类的实例,都首先触发基类的构造函数,然后触发派生类的构造函数
这就是它通常的样子:
public class MyClass : BaseClass
{
public MyClass (string p1, int p2, bool p3) : base (p1, p2)
{
P3 = p3;
}
}
我认为,如果您无法访问代码(如果它位于外部库中),就无法避免触发基类的构造函数。否则,您可以添加一个受保护的无参数构造函数,在这种情况下,您可以编写):base()
,也可以不使用它
如果您有权访问代码,则应该让构造函数仅在基类中触发虚拟或抽象方法,然后简单地重写该方法。最后,我提出了以下解决方案:
public class BaseValidator<T> : AbstractValidator<T>
{
#region Constructor
public BaseValidator(params string[] suppressPropertyValidations)
{
var type = typeof(T);
if (!hiddenPropertiesDictionary.ContainsKey(type))
{
lock (type)
{
if (!hiddenPropertiesDictionary.ContainsKey(type))
{
var notMappedProperties = new List<string>();
var hiddenProperties = from property in type.GetProperties()
where property.IsHidingMember()
select property.Name;
notMappedProperties.AddRange(hiddenProperties);
hiddenPropertiesDictionary.Add(type, notMappedProperties);
}
}
}
this.suppressPropertyValidations = new List<string>(suppressPropertyValidations);
}
#endregion
#region Fields & Properties
private static Dictionary<Type, List<string>> hiddenPropertiesDictionary = new Dictionary<Type, List<string>>();
private readonly List<string> suppressPropertyValidations;
#endregion
#region Fields & Properties
private IEnumerable<string> GetSuppressedPropertyValidation()
{
var type = typeof(T);
var hiddenProperties =
hiddenPropertiesDictionary.ContainsKey(type) ?
hiddenPropertiesDictionary[type] :
null;
return suppressPropertyValidations.Union(hiddenProperties);
}
public override ValidationResult Validate(ValidationContext<T> context)
{
var result = base.Validate(context);
var errors =
from suppressProperty in GetSuppressedPropertyValidation()
join error in result.Errors on suppressProperty equals error.PropertyName
select error;
foreach (var error in errors)
result.Errors.Remove(error);
return result;
}
#endregion
}
最后是DerivedClass
:
public class DerivedClassValidator : BaseClassValidator<DerivedClass>
{
public DerivedClassValidator()
: base("foo","bar")
//some arbitrary property names (other than the hidden ones e.g. MyProperty) that you want to be suppressed in the baseclass goes here.
{
//Some codes and Rules here.
}
}
公共类DerivedClassValidator:BaseClassValidator
{
公共派生类验证器()
:base(“foo”、“bar”)
//此处列出了您希望在基类中禁止的某些任意属性名称(隐藏名称除外,例如MyProperty)。
{
//这里有一些守则和规则。
}
}
您确定此处需要继承吗?每当您觉得需要使用new
关键字时,这就很好地表明您误用了继承——要么从错误的基类继承,要么使用继承而不是组合。当然,这是一条经验法则-也有例外,使用new
关键字隐藏继承的成员是最明智的做法。我不确定您的第二个代码片段是否有意义。您是否将属于方法或属性的代码直接放入类中?@Battle当然,我修复了它。
public class DerivedClassValidator : BaseClassValidator<DerivedClass>
{
public DerivedClassValidator()
: base("foo","bar")
//some arbitrary property names (other than the hidden ones e.g. MyProperty) that you want to be suppressed in the baseclass goes here.
{
//Some codes and Rules here.
}
}