attribute
  • 可利用于类型和成员
  • 是类的一个实例
  • 从System.Attribute派生
C# attribute应用范畴
  • 程序集
  • 模块
  • 类型(类、构造、枚举、接口、委托)
  • 字段
  • 办法(含结构器)
  • 办法参数
  • 办法返回值
  • 属性
  • 事件
  • 泛型类型参数
FCL定义的Attribute列举
  • Serializable:利用于类型,通知序列化格式化器,一个实例的字段能够呗序列化和反序列化
  • Flags:利用于枚举类型,将枚举类型作为一个位标记(bit flag)汇合应用
默认自定义的attribute类能用于任何指标元素
public class MyAttribute : Attribute{    public MyAttribute()    {    }}[MyAttribute]class Program{    [MyAttribute]    static void Main(string[] args)    {    }}

限定attribute的应用范畴:枚举类型

[AttributeUsage(AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]public class MyEnumAttribute : Attribute{    public MyEnumAttribute()    {    }}

以上代码利用AttributeUsage告知编译器定制attribute的非法利用范畴,如果将定制attribute利用于一个有效指标时将会报错

[MyEnumAttribute] //正确public enum MyEnum { }[MyEnumAttribute] //谬误:只对枚举无效class Program{}
AllowMultiple和Inherited
  • AllowMultiple:不显示设置为true就只能向一个选定指标利用一次
  • Inherited:指明在attribute利用于基类的时候是否同时利用于派生类和重写办法上
[AttributeUsage(AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]public class MyEnumAttribute : Attribute{    public MyEnumAttribute()    {    }}//谬误:个性反复[MyEnumAttribute][MyEnumAttribute]public enum MyEnum { }/*------------------------------*/[AttributeUsage(AttributeTargets.Enum, AllowMultiple = true, Inherited = false)]public class MyEnumAttribute : Attribute{    public MyEnumAttribute()    {    }}//正确[MyEnumAttribute][MyEnumAttribute]public enum MyEnum { }

定制attribute时能够应用结构器获取参数,在应用过程中,必须传递一个编译时常量表达式。传递参数规定:

  • Type类型参数:必须应用C#的typeof操作符传递
  • Object参数:可传递int、string或其它任意常量表达式(包含null),如果常量表达式为值类型,那么会在运行时结构attribute实例的时候对其装箱

示例代码:

/// <summary>/// 自定义Attribute/// </summary>/// <param name="name">援用string</param>/// <param name="o">任意类型,有必要就进行装箱</param>/// <param name="t">Type类型</param>public MyAttribute(string name, Object o, Type t){}class Program{    [MyAttribute("name", 12, typeof(string))]    static void Main(string[] args)    {    }}
利用反射查看类型attribute扭转代码的行为
[AttributeUsage(AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]public class MyEnumAttribute : Attribute{    public MyEnumAttribute()    {    }}[MyEnumAttribute]public enum MyEnum { }public void Test(Type enumType){    if(enumType.IsDefined(typeof(MyEnumAttribute), false)){        //如果含有MyEnumAttribute个性执行以下代码    }    else    {        //否则执行以下代码    }}
应用反射查看办法attribute个性
public class MyAttribute : Attribute{    public MyAttribute(string name, Object o, Type t) {}}[DebuggerDisplayAttribute("doubleJ", Name = "Name", Target = typeof(Program))]public class Program{    [Conditional("Debug")]    public void DoSomething() { }    [MyAttribute("name", 12, typeof(string))]    public static void Main(string[] args)    {        ShowAttribute(typeof(Program));        var members = typeof(Program).FindMembers(            MemberTypes.Method | MemberTypes.Constructor,            BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static,            Type.FilterName, "*"        );        foreach (var member in members)            ShowAttribute(member);        Console.ReadKey();    }    private static void ShowAttribute(MemberInfo memberInfo)    {        var attributes = Attribute.GetCustomAttributes(memberInfo);        foreach (var attribute in attributes)        {            Console.WriteLine(attribute.GetType().ToString());            if (attribute is MyAttribute)            {            }            if (attribute is ConditionalAttribute)            {            }            DebuggerDisplayAttribute dda = attribute as DebuggerDisplayAttribute;            if (dda != null)                Console.WriteLine("value = {0}, name = {1}, target = {2}", dda.Value, dda.Name, dda.Target);        }    }}

运行后果

IsDefined、GetCustomAttributes、GetCustomAttribute比照
  • IsDefined:有一个指定的Attribute派生类的实例与指标关联就返回true,因为不结构任何Attribute类的实例所以效率很高
  • GetCustomAttributes:返回一个数组,每个元素都是利用于指标的指定Attribute类的一个实例。如果不为该办法指定具体的Attribute,数组中曾经利用的所有Attribute的实例,如果没有利用任何Attribute类的实例返回空数组
  • GetCustomAttribute:返回利用于指标的指定Attribute类的一个实例。如果没有则返回null。如果利用了多个Attribute实例,则抛出异样

*应用IsDefined不会调用Attribute的结构器,也不会设置它的字段和属性,所以IsDefined效率最高,如果想要晓得一个Attribute是否利用于一个指标,那么应该抉择应用该办法

条件Attribute

应用条件Attribute后它的执行便会依赖于指定的预处理标识符,如:

[Conditional("DEBUG")][Conditional("TEST")]public class CondAttribute : Attribute{}

*当编译器发现指标元素应用了Conditional的一个实例,那么在含有指标元素的代码在进行编译时(以上述代码为例),只有在定义了TEST或DEBUG符号的前提下,编译器才会在元数据中生成attribute信息,尽管如此,但attribute类的定义元数据和实现依然存在于程序集中。

重写Match和Equals实现两个attribute实例的匹配
[Flags]public enum Role{    Read = 0x0001,    Write = 0x0002}sealed class RoleAttribute : Attribute{    private Role m_Role;    public RoleAttribute(Role role)    {        this.m_Role = role;    }    public override bool Match(object obj)    {        if (obj == null) return false;        if (this.GetType() != obj.GetType()) return false;        RoleAttribute other = (RoleAttribute)obj;        if ((other.m_Role & this.m_Role) != this.m_Role)            return false;        return true;    }    public override bool Equals(object obj)    {        if (obj == null) return false;        if (this.GetType() != obj.GetType()) return false;        RoleAttribute other = (RoleAttribute)obj;        if (other.m_Role != this.m_Role)            return false;        return true;    }    public override int GetHashCode()    {        return (Int32)this.m_Role;    }}[RoleAttribute(Role.Read)]class Role1 { }[RoleAttribute(Role.Write)]class Role2 { }public class Program{    public static void Main(string[] args)    {        CanRead(new Role1());        CanRead(new Role2());        Console.ReadKey();    }}private static void CanRead(object obj){    Attribute read = new RoleAttribute(Role.Read);    Attribute validRole = Attribute.GetCustomAttribute(obj.GetType(), typeof(RoleAttribute), false);    if((validRole!=null)&&read.Match(validRole))        Console.WriteLine("{0} can read", obj.GetType());    else        Console.WriteLine("{0} can not read", obj.GetType());}

输入后果