1,特性的应用范围:特性可应用于程序集,模块,类型,字段,方法,方法参数,方法返回值,属性,参数,泛型参数
2,利用前缀告诉编译器表明意图---下面的倾斜是必须的表明了我们的目标元素:
[assembly: AssemblyTitle("ClrFromCSharp_2_2")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ClrFromCSharp_2_2")] [assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // 将 ComVisible 设置为 false 会使此程序集中的类型 //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 //请将此类型的 ComVisible 特性设置为 true。 [assembly: ComVisible(true)] // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID [assembly: Guid("8c81c6c1-261e-445a-827d-fabe71033d57")] // 程序集的版本信息由下列四个值组成: // // 主版本 // 次版本 // 生成号 // 修订号 // //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //通过使用 "*",如下所示: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]
3,特性的本质是一个类型的实列,并且定制特性类必须从System.Attribute类派生
4,许多类:比如
StructLayoutAttribute
MarshalAsAttribute
DllImportAttribute
InAttribute
OutAttribute
都在命名空间System.Runtime.InteropServices命名空间中.
5,特性对象的构造,应为特性是类的实列,所以其支持类似
[DllImport("avifil32.dll"),CharSet=CharSet.Ansi)]//其中第一个为构造器参数,第二个为公共字段的值 private static extern void AVIFileInit();
6,定制特性的简化写法,
- 两个定制特性可以分开写也可以写一起(使用","分开)
- 定制特性没有先后顺序的区分
- 定制特性如果没有构造器参数,可以省略()
- 定制特性如果后缀是Attribute,可以省略,以下都一样.
[Serializable][Flags] [Serializable,Flags] [FlagsAttribute,SerializableAttribute] [FlagsAttribute(),SerializableAttribute()]
7,定义自己的特性类
假设需要定义类FlagsAttribute
[AttributeUsage(AttributeTargets.Enum,Inherited =false)] public class FlagsAttribute : Attribute { public FlagsAttribute() { } }
注意上面的AttributeUsage类
- 定制参数指明该定制特性的范围--AttributeTargets--比如Flags只能作用于枚举类
- 指定是否可以将特性用于同一目标 AllowMultiple
- 指定是否将特性应用于派生类和重写的方法:Inherited
- 特性类的实列构造器,字段和属性能用的数据类型并不多,只允许
- Boolean,Char,Byte,SByte,Int16,UInt16,Int32,UInt32,Int64,UInt64,Single,Double,String,Type,Object,Enum.
- 还可以使用上述类型的一维0基数组,但是应尽量避免使用数组.
8,检测定制特性
[AttributeUsage(AttributeTargets.All,Inherited =false)] public class Flags1Attribute : Attribute { public Flags1Attribute() { } } // [Flags1] public class TestAttribute { public TestAttribute() { if (this.GetType().IsDefined(typeof(Flags1Attribute), false)) Console.WriteLine("the object is Defined the Attribute Flags1"); else Console.WriteLine("the object is not Defined the Attribute Flags1"); } public static void Call() { TestAttribute a1 = new TestAttribute(); } }
使用IsDefined函数检测在类的实列中是否使用了特性!注意该方法在MemberInfo类中定义,注意,类Type派生自该类.
- IsDefined()该方法检测是否由指定的Attribute派生类的实列与目标关联
- GetCustomAttribute()---获取特性常用于multiple设为true
public static void Main() { try { // Get the type of MyClass1. Type myType = typeof(MyClass1); // Get the members associated with MyClass1. MemberInfo[] myMembers = myType.GetMembers(); // Display the attributes for each of the members of MyClass1. for(int i = 0; i < myMembers.Length; i++) { Object[] myAttributes = myMembers[i].GetCustomAttributes(true); if(myAttributes.Length > 0) { Console.WriteLine(" The attributes for the member {0} are: ", myMembers[i]); for(int j = 0; j < myAttributes.Length; j++) Console.WriteLine("The type of the attribute is {0}.", myAttributes[j]); } } } catch(Exception e) { Console.WriteLine("An exception occurred: {0}", e.Message); } }
当使用GetMembers方法可以获取某个类的所有公开类型,注意,方法,属性,字段,构造器等都是Member之一.
然后利用分别对每一个成员获取其特性属性集合.
9,CustomAttributeExtensions中定义的三个方法
|
说明 |
IsDefined | public static bool IsDefined (this System.Reflection.MemberInfo element, Type attributeType, bool inherit);//inherit指定是否检查其上级,true则检查,false不检查 public static bool IsDefined (this System.Reflection.Assembly element, Type attributeType); //检查某个程序集里面是否存在该特性 public static bool IsDefined (this System.Reflection.MemberInfo element, Type attributeType); //检查某个类的成员是否包含特定的特性 public static bool IsDefined (this System.Reflection.Module element, Type attributeType); //检查某个模块里面是否包含特定的特性 public static bool IsDefined (this System.Reflection.ParameterInfo element, Type attributeType); //检查某个方法里面的参数是否包含特定的特性 |
GetCustomAttributes | 与上述类似,用于获取某个对象(模块,程序集,type,memberinfo,parameterinfo,等)的特性的集合. 返回一个枚举集合. |
GetCustomAttribute | public static Attribute GetCustomAttribute (this System.Reflection.Assembly element, Type attributeType);//从某个对象里面直接获取这个特性实列. |
10,反射命名空间 System.Reflection 提供了几个类允许检查模块的元数据
- Assembly
- Module
- ParameterInfo
- MemberInfo
- Type
- MethodInfo
- ConstructorInfo
- FieldInfo
- EventInfo
- PropertyInfo
- 及各自的*Builder类
所有类都提供了IsDefined和GetCustomAttributes方法.
11,检测定制特性 注意----MemberInfo--->Type---->TypeInfo.
利用Type
可以获得
- 类的方法
- 类的成员
- 类的字段
- 类的属性
- 类的构造器等
TypeInfo t = typeof(Calendar).GetTypeInfo();
IEnumerable<PropertyInfo> pList = t.DeclaredProperties;
IEnumerable<MethodInfo> mList = t.DeclaredMethods;
查看定制类的方法:
[Serializable] [DefaultMember("Main")] [DebuggerDisplay("Maoxiongbin",Name ="Mao",Target =typeof(CheckAttributeRef))] public sealed class CheckAttributeRef//上面特性用于定义类的特性. { [Conditional("Debug")] [Conditional("Release")] public void DoSomething() { }//上面两个特性用于定义Dosomething方法 public CheckAttributeRef() { }//没有特性御用构造器 [CLSCompliant(true)] [STAThread] public static void Go()//2个特性用于静态方法GO() { ShowAttributes(typeof(CheckAttributeRef));//查看奔雷的特性情况 var members = from m in typeof(CheckAttributeRef).GetTypeInfo().DeclaredMembers.OfType<MethodBase>()//使用GetTypeInfo()返回TypeInfo对象,然后调用 where m.IsPublic//DeclareMembers获取其成员,然后删选必须时类别MethodBase的派生类,MethodInfo和ConstructInfo两类.....并且是公共的 select m; members.ToList<MethodBase>().ForEach(x => ShowAttributes(x));//执行特性输出 } private static void ShowAttributes(MemberInfo AttributeTargets) { var attr = AttributeTargets.GetCustomAttributes<Attribute>();//MemberInfo是基类--是MethodInfo和ConstructInfo的基类,利用Extensions扩展函数获取成员中的特性. Console.WriteLine("Attribute applied to {0}:{1}", AttributeTargets.Name, (!attr.Any() ? "None" : String.Empty));//成员名称,成员中定制特性数量... foreach(Attribute attribute in attr)//针对不同特性输出不同信息. { Console.WriteLine("{0}", attribute.GetType().ToString()); if (attribute is DefaultMemberAttribute) Console.WriteLine("MemberName={0}", ((DefaultMemberAttribute)attribute).MemberName); if (attribute is ConditionalAttribute) Console.WriteLine("ConditionString={0}", ((ConditionalAttribute)attribute).ConditionString); if (attribute is CLSCompliantAttribute) Console.WriteLine("IsCompliant={0}", ((CLSCompliantAttribute)attribute).IsCompliant); if(attribute is DebuggerDisplayAttribute) { DebuggerDisplayAttribute d = (DebuggerDisplayAttribute)attribute; Console.WriteLine("Value={0},Name={1},Target={2}", d.Value, d.Name, d.Target); } } Console.WriteLine(); } } }
12,类的特性匹配
12.1新建一个枚举类型 Accounts
[Flags] internal enum Accounts { Savings=0x0001, Checking=0x0002, Brokerage=0x0004 }
12.2新建一个账号等级特性
[AttributeUsage(AttributeTargets.Class)]//该特性只能在类上面 internal sealed class AccountsAttribute : Attribute//定义Accounts特性 { private Accounts m_accounts; public AccountsAttribute(Accounts accounts)//构造函数 { m_accounts = accounts; } public override bool Match(object obj)//重写Match函数,定义匹配特性. { if (obj == null) return false;//如果obj是null则返回 if (this.GetType() != obj.GetType()) return false;//如果类型不匹配,则返回. var other = obj as AccountsAttribute; if ((other.m_accounts & m_accounts) != m_accounts)//判断other的m_accounts是否包含了this.m_accounts的信息. return false; return true; } public override bool Equals(object obj)//重写该函数,检查两个特性是否相等. { if (obj == null) return false; if (this.GetType() != obj.GetType()) return false; var other = obj as AccountsAttribute; return other.m_accounts == m_accounts; } public override int GetHashCode()//重写了Equals,必须重写该函数. { return (int)m_accounts; } } [Accounts(Accounts.Savings)] internal sealed class ChildAccount { }//定义测试的类,并且定制特性对象Accounts,初始化为Accounts.Savings. [Accounts((Accounts)7)]//定义测试的类,并且定制特性对象Accounts,初始化为Accounts.Savings|Checking|Brokerage internal sealed class AdultAccount { }//(Accounts)7进行转换.
12.3创建一个测试函数
private static void CanWriteCheck(object obj) { Attribute checking = new AccountsAttribute(Accounts.Checking);//创建特性类对象 Attribute validAccounts = obj.GetType().GetCustomAttribute(typeof(AccountsAttribute));//从类中获取嵌入的特性类对象 if ((validAccounts != null) && (checking.Match(validAccounts)))//利用Match函数判断是否符合条件 Console.WriteLine("{0} types can write checks.", obj.GetType()); else Console.WriteLine("{0} types can not write checks.", obj.GetType()); }
`12.4测试和结果
public static void GoAttributeMatch() { CanWriteCheck(new ChildAccount());//测试CHild类 CanWriteCheck(new AdultAccount());//测试Adult类 CanWriteCheck(new CheckAttributeRef());//测试CHeck类 }
//结果
ClrFromCSharp_2_2.LearnAttribute.ChildAccount types can not write checks.
ClrFromCSharp_2_2.LearnAttribute.AdultAccount types can write checks.//类的特性中由checking
ClrFromCSharp_2_2.LearnAttribute.CheckAttributeRef types can not write checks.
//
//
//
13,条件特性类----在特性类前面加入 特[Conditional("Test1"),Conditional("Test2")] 来控制,只有在当前文件下,定义了
#define Test1 或者 #define Test2 才能够生成特性实列.
[Conditional("TEST"),Conditional("VERIFY")] [AttributeUsage(AttributeTargets.All)] public sealed class CondAttribute : Attribute { }
也就是说,特性CondAttribute只有在由#define Test 或者#define VERIFY的情况下才有效
public sealed class CondTest { public static void Go() { Console.WriteLine("CondAttribute is {0} applied to {1} type", (typeof(CondTest).IsDefined(typeof(CondAttribute),false)) ? "" : "not", typeof(CondTest).ToString()); } }