C#如何获知一个元素是否申明了某个特性?

在.NET中提供了很多的方法来查询一个元素是否申明了某个特性,每个方法都有不同的使用场合,但是万变不离其宗,都是基于反射机制来实现的。

首先,还是以上面的MyCustomAttribute特性为例,新建一个入口方法类Program:.

/// <summary>
/// 一个自定义特性MyCustomAttribute
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute
{
    private string className;

    public MyCustomAttribute(string className)
    {
        this.className = className;
    }

    // 一个只读属性ClassName
    public string ClassName
    {
        get
        {
            return className;
        }
    }
}

[MyCustom("Program")]
class Program
{
    static void Main(string[] args)
    {
        Type attributeType = typeof(MyCustomAttribute);
        Type thisClass = typeof(Program);
        
    }
}

(1)System.Attribute.IsDefined方法

// 使用IsDefined方法
bool isDefined = Attribute.IsDefined(thisClass, attributeType);
Console.WriteLine("Program类是否申明了MyCustomAttribute特性:{0}", isDefined);

(2)System.Attribute.GetCustomerAttribute方法

// 使用Attribute.GetCustomAttribute方法
Attribute att = Attribute.GetCustomAttribute(thisClass, attributeType);
if (att != null)
{
    Console.WriteLine("Program类申明了MyCustomAttribute特性,特性的成员为:{0}", (att as MyCustomAttribute).ClassName);
}

(3)System.Attribute.GetCustomerAttributes方法

// 使用Attribute.GetCustomAttributes方法
Attribute[] atts = Attribute.GetCustomAttributes(thisClass, attributeType);
if (atts.Length > 0)
{
    Console.WriteLine("Program类申明了MyCustomAttribute特性,特性名称为:{0}", ((MyCustomAttribute)atts[0]).ClassName);
}

(4)System.Reflection.CustomAttributeData类型

// 使用CustomAttributeData.GetCustomAttributes方法
IList<CustomAttributeData> attList = CustomAttributeData.GetCustomAttributes(thisClass);
if (attList.Count > 0)
{
    Console.WriteLine("Program类申明了MyCustomAttribute特性");
    // 注意:这里可以对特性进行分析,但无法得到其实例
    CustomAttributeData attData = attList[0];
    Console.WriteLine("该特性的名字是:{0}", attData.Constructor.DeclaringType.Name);
    Console.WriteLine("该特性的构造方法有{0}个参数", attData.ConstructorArguments.Count);
}

下图是四种方式的执行结果:

C#如何获知一个元素是否申明了某个特性?

这四种方法各有其特点,但都可以实现查询某个元素是否申明了某个特性的这一功能。其中,可以看到第(4)种方式,可以对特性进行分析,但无法得到其实例。另外,自定义特性被申明为sealed表示不可继承,这是因为在特性被检查时,无法分别制定特性和其派生特性,这一点需要我们注意