溫故而知新:c#中的特性(attribute)

weixin_34293059發表於2010-03-30

特性(Attribute)是微軟在.Net中自創的一種新技術,對於很多初學者來講,特性一直是一塊難啃的骨頭。

既然弄不懂,那我們就暫時繞過它吧,回想一下我們在寫程式碼時通常都要求寫註釋,為了是讓別人或自己以後能看得懂,但是這個註釋是寫給“人”看的,突發奇想一下:我們能不能寫出一種註釋,給c#編譯器看,比如我們在某些程式碼上打個標記,讓編譯器看到這些標記後,做出不同的反應?

其實...這就是特性,比如我們定義一個常規的類

public class Product
{
   public string Name { set; get; }
   public decimal Price { set; get; }
}

常規這樣編譯時,Product並不支援序列化,但只要我們在前面加上一行程式碼,比如:

[Serializable]
public class Product
{
    public string Name { set; get; }
    public decimal Price { set; get; }
}

編譯器在編譯時就能做出反應:哦,原來Product要求支援序列化,我曉得了 :)

這裡的[Serializable]就是一個特性,一個類被應用該特性後,編譯器編譯時會查詢SerializableAttribute這個類(即:自動新增Attribute字尾),並檢測該類是否繼承自Attribute,如果找到則會呼叫SerializableAttribute的預設構造器生成一個該類的例項,然後會生成相應的資訊一起附加到Product類的後設資料裡,然後這些附加的特性後設資料,可以通過反射呼叫。

下面這些程式碼摘自Anytao的大作"您必須知道的.Net"一書:

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
        {
            set { _memo = value; }
            get { return _memo; }
        }

        public void ShowName()
        {
            Console.WriteLine("Hello,{0}", _name == null ? "word." : _name);
        }

    }

上面定義了一個特性類,單獨看它跟普通類沒有任何區別,下面看一下如何應用:

[Myself("Emma", 25, Memo = "my good girl.")]   
    public class Mytest
    {
        public void SayHello()
        {
            Console.WriteLine("Hello,my.net world.");
        }
    }

這裡將剛才的MyselfAttribute特性應用到Mytest類上面了,注意寫法:字尾Attribute可以省略

[Myself("Emma", 25, Memo = "my good girl.")]

這一行的含義相當於

new MyselfAttribute("Emma",25){Memo = "my good girl."}

最後看一下如何應用:

using System;
using System.Reflection;
...

static void Main(string[] args)
{
    Type info = typeof(Mytest);

    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 = info.GetMethod("SayHello");
    mi.Invoke(obj, null);
    Console.ReadLine();

}

執行結果:

Name:Emma
Age:25
Memo of Emma is my good girl.
Hello,Emma
Hello,my.net world.

這裡解釋一下:假如Mytest沒有應用MyselfAttribute的話,MyselfAttribute myattribute = (MyselfAttribute)Attribute.GetCustomAttribute(info, typeof(MyselfAttribute)) 肯定會返回null,而正是因為應用了特性之後,才能得到這些附加的特性資訊,從而在if包含的程式碼塊中利用反射呼叫成功。

最後要指出的是:attribute在使用中,還能指定應用的目標物件(比如我們可以只讓某特性應用於某一個Method或Field,預設情況下特性可應用於所有型別的目標),除此之外,還能指定該特性是否能應用多次...詳情請參閱MSDN上的Attribute類

 

相關文章