【问题标题】:Custom Validation Attribute自定义验证属性
【发布时间】:2020-01-27 11:47:08
【问题描述】:

目前我尝试通过同一类的另一个属性来验证一个属性。我收到一条错误消息,告诉我以下内容:

非静态字段、方法或属性需要对象引用

对于下面的代码 sn-p,这种错误对我来说绝对有意义。但无论如何,由于属性 B 的值(在我的示例级别中),我尝试验证属性 A(在我的示例 OrderNumber 中)。

是否有可能通过使用验证注释来做到这一点?

这是我目前的代码:

    public class A
    {
        /// <summary>
        /// Level 
        /// </summary>
        public string Level { get; set; }

        public B B {get;set;}
    }

    public class B
    {
        /// <summary>
        /// Order Number
        /// </summary>
        [Level(A.Level)]
        public int? OrderNumber { get; set; }
    }



    public class LevelAttribute : ValidationAttribute
    {

        private string Dlevel { get; set; }

        public LevelAttribute(string dlevel)
        {
            this.Dlevel = dlevel;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value!=null && (Dlevel.Equals("D1")||Dlevel.Equals("D2")))
            {
                return new ValidationResult("Invalid Error Message");
            }
            return ValidationResult.Success;
        }
    }

感谢您的帮助。

【问题讨论】:

  • 属性参数必须是常量值,IIRC
  • 不可能链接动态数据域?
  • 不,据我所知没有...

标签: c# .net-core validationmessage


【解决方案1】:

在自定义属性构造函数中不能直接引用实例成员(方法、属性、字段)。但是有一种间接的方式,就是定义属性名,通过反射解析对应的属性值:

public class A
{
    public A()
    {
        Level = "D3";
    }

    public string Level { get; set; }

    public B B { get; set; }
}

public class B
{
    [Level("MyNamespace.A.Level")]
    public int? OrderNumber { get; set; }
}

public class LevelAttribute : ValidationAttribute
{
    private string PropName { get; set; }

    public LevelAttribute(string prop)
    {
        this.PropName = prop;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        System.Reflection.PropertyInfo property = null;
        object objectinstance = null;

        if (this.PropName.Contains("."))
        {
            string classname = PropName.Substring(0, PropName.LastIndexOf("."));
            string prop = PropName.Substring(PropName.LastIndexOf(".") + 1);
            Type type = Type.GetType(classname);

            objectinstance = System.Activator.CreateInstance(type);
            property = type.GetProperty(prop, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
        }
        else
        {
            objectinstance = validationContext.ObjectInstance;
            property = validationContext.ObjectInstance.GetType().GetProperty(this.PropName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
        }

        object propertyvalue = property.GetValue(objectinstance, new object[0]);

        if (value != null && propertyvalue != null && (propertyvalue.Equals("D1") || propertyvalue.Equals("D2")))
        {
            return new ValidationResult("Invalid Error Message");
        }
        return ValidationResult.Success;
    }
}

【讨论】:

  • 我编辑了我的第一个问题,因为现实中存在其他代码结构。你能给我一个提示吗?
  • 要访问其他类的实例属性,您需要实例类对象(通过“new A()”创建)。如果 Level 属性是静态的,那就有办法了。另一种解决方案是在 IsValid() 方法中动态创建类 A 并通过反射读出属性。如果您可以接受这种方法,我可以更新我的示例代码。
  • 我已经更新了代码。现在您可以通过定义完整的属性路径(包括命名空间)来设置另一个类的属性。如您所见,A 类是动态创建的以获取 Level 属性。
  • 顺便说一句,对于 B 类,您可以添加一个引用 A 类实例的“父”属性。这样您就可以访问 level 属性,而无需为 A 类创建新实例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多