Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 抑制基类属性验证以支持派生类重写的属性验证_C#_Asp.net Core_Fluentvalidation - Fatal编程技术网

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.
    }
}