C#属性方法的用法

时间:2019-03-12 08:55:50

标签: c# attributes

在C#中,在属性中声明的方法的目的是什么?如何使用它们?

作为一个例子,看看属性MaxLengthAttribute:它有很多方法。其中的一种是IsValid()方法,该方法用于验证应用属性的属性。该验证如何执行?我想针对属性调用了IsValid()方法,但是我没有找到有关如何调用属性方法的文档。

注意:我有Java背景。在Java中,注释旨在用作元数据,并且声明为use,因此它们没有方法。

3 个答案:

答案 0 :(得分:2)

在几乎所有情况下,答案都是简单的:手动但使用不是您自己的代码。您正在使用的某些框架中的某些代码有意检查这些属性,然后检查它们是否存在:实现它们(最好还进行某种缓存),然后调用该方法。 / p>

属性本身不会做任何事情,但是它们仍然是类型,可以通过反射API来实现。如果要编写代码来做到这一点:

using System;

[SomeAttribute("boop")]
static class P
{
    static void Main()
    {
        var obj = (SomeAttribute)Attribute.GetCustomAttribute(
            typeof(P), typeof(SomeAttribute));

        // note the attribute doesn't know the context
        // so we need to pass that *in*; an attribute
        // doesn't know what it has been attached to
        obj?.DoSomething(typeof(P));
    }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct
    | AttributeTargets.Enum)]
class SomeAttribute : Attribute
{
    public string Name { get; }
    public SomeAttribute(string name)
        => Name = name;
    public void DoSomething(Type type)
        => Console.WriteLine($"hey {type.Name} - {Name}");
}

答案 1 :(得分:1)

基本上,属性本身不执行任何操作,必须通过某种框架进行分析。该框架实际执行的操作完全取决于属性创建者。因此,框架可以只检查属性是否存在,但是当然也可以调用其成员。

因此,假设您有以下代码:

[MyAttribute]
class MyClass
{
}

class MyAttribute : Attribute
{
    public void DoSomething();
}

现在您有一些代码可以检查属性是否存在,如果存在则调用DoSomething

// get types with the attribute
var typesAndAttributes= myAssembly.GetTypes().Select(x => new 
    { 
        Type = x, 
        Attribute = Attribute.GetCustomAttribute(x, typeof(MyAttribute)) 
    });

// now call DoSomething for every attribute
forerach(var e in typesAndAttributes)
{
    e.Attribute?.DoSomething();
}

在您的MaxLengthAttribute示例中,这意味着以下内容。如果您要像这样装饰您的会员:

MaxLengthAttribute(2)
public int[] MyArr = new int[3];

并执行框架为IsValid调用MyArr的代码,可能会(不确定,不检查源代码)返回false,因为该值包含3个元素,尽管只有两个被认为是有效的。

答案 2 :(得分:0)

  

作为一个例子,看看属性MaxLengthAttribute:它有很多方法。其中之一是IsValid()方法,该方法用于验证应用属性的属性。该验证如何执行?我想针对属性调用了IsValid()方法,但是我没有找到有关如何调用属性方法的文档。

这是一个非常简单的示例:

// Start off with an object we're going to validate
public class Foo
{
    [MaxLength(5)]
    public string Bar { get; set; } 
}

var objectToValidate = new Foo() { Bar = "123456" };

// Use reflection to get a list of properties on the object
var properties = objectToValidate.GetType().GetProperties();

foreach (var property in properties)
{
    // For each property, get the attributes defined on that property
    // which derive from the ValidationAttribute base class
    var attributes = property.GetCustomAttributes<ValidationAttribute>();

    var propertyValue = property.GetValue(objectToValidate);

    foreach (var attribute in attributes)
    {
        // For each attribute, call its IsValid method, passing in the value
        // of the property
        bool isValid = attribute.IsValid(propertyValue);
        if (!isValid)
        {
            Console.WriteLine("{0} is invalid", property.Name); 
        }
    }
}

这与Validator.ValidateObject差不多,除了更多的缓存。

(对于DataAnnotations方法,实际上使用TypeDescriptor基础结构。这使您可以有效地向类及其属性添加属性,而无需直接修改类的源)。

Runnable example