c#:定義特性

c#編程基礎之二:特性 這裏的特性區別於屬性,雖然msdn中似乎並沒有區別二者。
屬性:是面向對象編程的基本概念,提供了對私有字段的訪問封裝,在C#中以get和set訪問器方法實現對可讀可寫屬性的操作,提供了安全和靈活的數據訪問封裝。
特性:公共語言運行時允許添加類似關鍵字的描述聲明,叫做attributes, 它對程序中的元素進行標註,如類型、字段、方法和屬性等。Attributes和Microsoft .NET Framework文件的元數據保存在一起,可以用來向運行時描述你的代碼,或者在程序運行的時候影響應用程序的行爲。比如 [Serializable]、[Flags]、[DllImport]、[AttributeUsage]


    我們簡單的總結爲:定製特性attribute,本質上是一個類,其爲目標元素提供關聯附加信息,並在運行期以反射的方式來獲取附加信息。

    我理解的定製特性,就是爲目標元素,可以是數據集、模塊、類、屬性、方法、甚至函數參數等加入附加信息,類似於註釋,但是可以在運行期以反射的方式獲得。定製特性主要應用在序列化、編譯器指令、設計模式等方面。

一、通用規則:
    1、定製特性可以應用的目標元素可以爲:程序集(assembly)、模塊(module)、類型(type)、屬性(property)、事件(event)、字段(field)、方法(method)、參數(param)、返回值(return),應該全了。

    2、定製特性以[,]形式展現,放在緊挨着的元素上,多個特性可以應用於同一元素,特性間以逗號隔開,以下表達規則有效:[AttributeUsage][ Flags]、[AttributeUsage, Flags]、[Flags, AttibuteUsageAttribute]、[AttributeUsage(), FlagesAttribute()]
    3、attibute實例,是在編譯期進行初始化,而不是運行期。
    4、C#允許以指定的前綴來表示特性所應用的目標元素,建議這樣來處理,因爲顯式處理可以消除可能帶來的二義性。例如: 

        using System;
        namespace Anytao.net
        {
              [assembly: MyAttribute(1)]          //應用於程序集
              [moduel: MyAttribute(2)]            //應用於模塊
              pubic class Attribute_how2do
              {
                 //
              }
        }
    5、定製特性類型,必須直接或者間接的繼承自System.Attribute類,而且該類型必須有公有構造函數來創建其實例。
    6、所有自定義的特性名稱都應該有個Attribute後綴,這是習慣性約定。
    7、定製特性也可以應用在其他定製特性上,這點也很好理解,因爲定製特性本身也是一個類,遵守類的公有規則。例如很多時候我們的自定義定製特性會應用AttributeUsageAttribute特性,來控制如何應用新定義的特性。             [AttributeUsageAttribute(AttributeTarget.All),
    AllowMultiple = true,
    Inherited = true]
    class MyNewAttribute: System.Attribute
    {
    //
    }
    8、定製特性不會影響應用元素的任何功能,只是約定了該元素具有的特質。
    9、所有非抽象特性必須具有public訪問限制。
    10、特性常用於編譯器指令,突破#define, #undefine, #if, #endif的限制,而且更加靈活。
    11、定製特性常用於在運行期獲得代碼註釋信息,以附加信息來優化調試。 
    12、定製特性可以應用在某些設計模式中,如工廠模式。
    13、定製特性還常用於位標記,非託管函數標記、方法廢棄標記等其他方面。
二、應用
    1、常用特性
也就是.NET已經提供的固有特性,事實上在.NET框架中已經提供了豐富的固有特性由我們發揮。

    AttributeUsage:用於控制如何應用自定義特性到目標元素。

    Flags:以Flags特性來將枚舉數值看作位標記,而非單獨的數值,例如:

enum Animal
{
     Dog     = 0x0001,
     Cat     = 0x0002,
     Duck    = 0x0004,
   Chicken = 0x0008
}
因此,以下實現就相當輕鬆,

Animal animals = Animal.Dog | Animal.Cat;
Console.WriteLine(animals.ToString());
請猜測結果是什麼,答案是:"Dog, Cat"。如果沒有Flags特性,這裏的結果將是"3"。

    DllImport:DllImport特性,可以讓我們調用非託管代碼,所以我們可以使用DllImport特性引入對Win32 API函數的調用,對於習慣了非託管代碼的程序員來說,這一特性無疑是救命的稻草。

    Serializable:表明了應用的元素可以被序列化

    Conditional:用於條件編譯,在調試時使用。注意:Conditional不可應用於數據成員和屬性。
三、自定義特性
    既然attribute,本質上就是一個類,那麼我們就可以自定義更特定的attribute來滿足個性化要求,只要遵守上述的12條規則,實現一個自定義特性其實是很容易的,典型的實現方法爲:

1、定義特性

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
     public class TestAttribute : System.Attribute
     {
         public TestAttribute(string message)
         {
             Console.WriteLine(message);
         }
         public void RunTest()
         {
             Console.WriteLine("TestAttribute here.");
         }
     }

2、應用目標元素 
        [Test("Error Here.")]
         public void CannotRun()
         {
             //
         }
3、獲取元素附加信息
    如果沒有什麼機制來在運行期來獲取Attribute的附加信息,那麼attribute就沒有什麼存在的意義。因此,.NET中以反射機制來實現在運行期獲取attribute信息,實現方法如下: 

         public static void Main()

         {
             Tester t = new Tester();
             t.CannotRun();

             Type tp = typeof(Tester);
             MethodInfo mInfo = tp.GetMethod("CannotRun");           
             TestAttribute myAtt = (TestAttribute)Attribute.GetCustomAttribute(mInfo, typeof(TestAttribute));
             myAtt.RunTest();
         }

 


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/changyuming/archive/2008/10/07/3027341.aspx

發佈了7 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章