学习参考:html
今天在讨论IPC通讯契约的时候,卢工提到使用Attribute来描述具体的接口方法的命令信息。发现对 Attribute的概念还不是很熟悉,所以对其进行学习梳理。正则表达式
一、Attribute是什么?它有什么用?函数
先来看看官方的定义:学习
msdn文档对它的描述:公共语言运行时容许添加相似关键字的描述声明,叫作attributes, 它对程序中的元素进行标注,如类型、字段、方法和属性等。Attributes和Microsoft .NET Framework文件的元数据保存在一块儿,能够用来向运行时描述你的代码,或者在程序运行的时候影响应用程序的行为。
简单的定义: 本质上是一个类,其为目标元素提供关联附加信息,并在运行期以反射的方式来获取附加信息。具体的特性实现方法,在接下来的讨论中继续深刻。测试
看定义老是有距离感,仍是看看实际的应用吧。spa
二、经常使用场景.net
.NET中常见的Attribute:调试
#define DEBUG //这里定义条件 using System; using System.Runtime.InteropServices; using System.Diagnostics; namespace AttributeDemo { class MainProgramClass { [DllImport("User32.dll")] public static extern int MessageBox(int hParent, string Message, string Caption, int Type); static void Main(string[] args) { DisplayRunningMessage(); DisplayDebugMessage(); MessageBox(0, "Hello", "Message", 0); Console.ReadLine(); } [Conditional("DEBUG")] private static void DisplayRunningMessage() { Console.WriteLine("开始运行Main子程序。当前时间是" + DateTime.Now); } [Conditional("DEBUG")] [Obsolete] private static void DisplayDebugMessage() { Console.WriteLine("开始Main子程序"); } } }
若是在一个程序元素前面声明一个Attribute,那么就表示这个Attribute被施加到该元素上,前面的代码,[DllImport]施加到MessageBox函数上, [Conditional]施加到DisplayRuntimeMessage方法和DisplayDebugMessage方法,[Obsolete]施加到DisplayDebugMessage方法上。Attribute类是在编译的时候被实例化的,而不是像一般的类那样在运行时候才实例化。code
三、自定义特性htm
一、自定义的Attribute必须直接或者间接继承System.Attribute。
二、全部自定义的特性名称都应该有个Attribute后缀,命名规范为:"类名"+Attribute
三、使用AttributeUsage来限定你的Attribute 所施加的元素的类型,AttributeUsage自己也是一个Attribute。它有一个带参数的构造器,这个参数是AttributeTargets的枚举类型
public enum AttributeTargets { All=16383, Assembly=1, Module=2, Class=4, Struct=8, Enum=16, Constructor=32, Method=64, Property=128, Field=256, Event=512, Interface=1024, Parameter=2048, Delegate=4096, ReturnValue=8192 }
此外,AttributeUsage还定义了如下三个属性:
AllowMultiple::读取或者设置这个属性,表示是否能够对一个程序元素施加多个Attribute 。
Inherited:读取或者设置这个属性,表示是否施加的Attribute 能够被派生类继承或者重载。
ValidOn::读取或者设置这个属性,指明Attribute 能够被施加的元素的类型。
下面是一个自定义特性的例子,摘自这里:
using System; using System.Reflection; //应用反射技术得到特性信息 namespace Anytao.net { //定制特性也能够应用在其余定制特性上, //应用AttributeUsage,来控制如何应用新定义的特性 [AttributeUsageAttribute(AttributeTargets.All, //可应用任何元素 AllowMultiple = true, //容许应用屡次 Inherited = false)] //不继承到派生类 //特性也是一个类, //必须继承自System.Attribute类, //命名规范为:"类名"+Attribute。 public class MyselfAttribute : System.Attribute { //定义字段 private string _name; private int _age; private string _memo; //必须定义其构造函数,若是不定义有编译器提供无参默认构造函数 public MyselfAttribute() { } public MyselfAttribute(string name, int age) { _name = name; _age = age; } //定义属性 //显然特性和属性不是一回事儿 public string Name { get { return _name == null ? string.Empty : _name; } } public int Age { get { return _age; } } public string Memo { get { return _memo; } set { _memo = value; } } //定义方法 public void ShowName() { Console.WriteLine("Hello, {0}", _name == null ? "world." : _name); } } //应用自定义特性 //能够以Myself或者MyselfAttribute做为特性名 //能够给属性Memo赋值 [Myself("Emma", 25, Memo = "Emma is my good girl.")] public class Mytest { public void SayHello() { Console.WriteLine("Hello, my.net world."); } } public class Myrun { public static void Main(string[] args) { //如何以反射肯定特性信息 Type tp = typeof(Mytest); MemberInfo info = tp; MyselfAttribute myAttribute = (MyselfAttribute)Attribute.GetCustomAttribute(info, typeof(MyselfAttribute)); if (myAttribute != null) { //嘿嘿,在运行时查看注释内容,是否是很爽 Console.WriteLine("Name: {0}", myAttribute.Name); Console.WriteLine("Age: {0}", myAttribute.Age); Console.WriteLine("Memo of {0} is {1}", myAttribute.Name, myAttribute.Memo); myAttribute.ShowName(); } //多点反射 object obj = Activator.CreateInstance(typeof(Mytest)); MethodInfo mi = tp.GetMethod("SayHello"); mi.Invoke(obj, null); Console.ReadLine(); } } }
FlagsAttribute属性就是枚举类型的一项可选属性。它的主要做用是能够将枚举做为位域处理,所谓位域是单个存储单元内相邻二进制位的集合。在.Net framework中有不少枚举都是用FlagsAttribute特性修饰,例如:正则表达式选项System.Text.RegularExpressions.RegexOptions、文件监视中的文件改变类型System.IO.WatcherChangeTypes、System.Web.UI.WebControls.DataControlRowState等等。
使用FlagsAttribute须要注意:
一、只有要对数值执行按位运算(AND、OR、XOR)时才对枚举使用 FlagsAttribute 自定义属性。
2.、必须用 2 的幂(即 一、二、四、8 等)定义枚举常量。
using System; class FlagsAttributeDemo { enum Color1 : short { Black = 0, Red = 1, Green = 2, Blue = 4 }; [FlagsAttribute] enum Color2 : short { Black = 0, Red = 1, Green = 2, Blue = 4 }; static void Main() { Console.WriteLine("测试未使用FlagsAttribute属性"); Color1 MyColor1 = Color1.Red | Color1.Blue & Color1.Green; //我先不运行计算一下看看是那个:0001|0100&0010=0001 应该是Red Console.WriteLine("MyColor1={0}", MyColor1); Color1 MyColor_1 = Color1.Red | Color1.Blue; //我先不运行计算一下看看是那个:0001|0100=0101 应该是5 Console.WriteLine("MyColor_1={0}",MyColor_1); Console.WriteLine("测试使用FlagsAttribute属性"); Color2 MyColor2 = Color2.Red | Color2.Blue; //我先不运行计算一下看看是那个:0001|0100=0101应该是Red,Blue Console.WriteLine("MyColor2={0}", MyColor2); Console.ReadKey(); } }