C#学习笔记 -- Attribute

学习参考:html

今天在讨论IPC通讯契约的时候,卢工提到使用Attribute来描述具体的接口方法的命令信息。发现对 Attribute的概念还不是很熟悉,所以对其进行学习梳理。正则表达式

一、Attribute是什么?它有什么用?函数

先来看看官方的定义:学习

msdn文档对它的描述:公共语言运行时容许添加相似关键字的描述声明,叫作attributes, 它对程序中的元素进行标注,如类型、字段、方法和属性等。Attributes和Microsoft .NET Framework文件的元数据保存在一块儿,能够用来向运行时描述你的代码,或者在程序运行的时候影响应用程序的行为。

简单的定义 本质上是一个类,其为目标元素提供关联附加信息,并在运行期以反射的方式来获取附加信息。具体的特性实现方法,在接下来的讨论中继续深刻。测试

看定义老是有距离感,仍是看看实际的应用吧。spa

二、经常使用场景.net

.NET中常见的Attribute:调试

  • Conditional:起条件编译的做用,只有知足条件,才容许编译器对它的代码进行编译。通常在程序调试的时候使用。
  • DllImport:用来标记非.NET的函数,代表该方法在一个外部的DLL中定义。
  • Obsolete:这个属性用来标记当前的方法已经被废弃,再也不使用了。
  • Serializable:代表应用的元素能够被序列化
#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修饰枚举

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();
    }
}
相关文章
相关标签/搜索