特性Attribute概述
特性(Attribute)是一種特殊的類型,可以加載到程序集或者程序集的類型上,這些類型包括模塊、類、接口、結構、構造函數、方法、字段等,加載了特性的類型稱之為特性的目標。這裡為與屬性(Property)區分,所以稱之為特性(Attribute)。特性是為程序集添加元數據的一種機制,通過它可以為編譯器提供指示或者對數據進行說明。例如前段時間學習的Remoting技術(主要用於應用程序域之間的對象通信)中在應用程序域間的引用對象時該對象具有序列化(Serializable)這個特性。下面使用ObsoleteAttribute特性學習特性的使用方法。
System.ObsoleteAttribute實例
我們有一個舊的方法SendMsg()方法由於功能和效率上的優化重載了這個方法,需要將原來的方法加上Obsolete特性告訴編譯器這個方法已經過時,然後編譯器發現程序中有地方使用該特性標記過的方法時,就會給出一個如下所示警告信息:
測試代碼如下所示:
using System; namespace AttributeTest { /// <summary> /// 信息實體類 /// </summary> public class Message { //此處具體實現略 } /// <summary> /// 信息操作類 /// </summary> public class MessageOperation { [Obsolete("請使用新的SendMsg(Message msg)重載方法")] public static void SendMsg() { Console.WriteLine("這是舊的SendMsg方法"); } public static void SendMsg(Message msg) { Console.WriteLine("這是新的SendMsg方法"); } } class Program { static void Main(string[] args) { //使用舊的方法SendMsg() MessageOperation.SendMsg(); //使用新的方法SendMsg(Message msg) MessageOperation.SendMsg(new Message()); } } }
這樣一來,開發人員編譯運行時就看到了"請使用新的SendMsg(Message msg)重載方法"警告,然後就知道應該選用新的SendMsg(Message msg)重載方法。通過上面的例子可以看到特性使用的方法:首先是一對方括號“[]”,在左方括號中後緊跟特性的名稱,比如Obsolete。隨後是一個圓括號“()”,在這個圓括號中,不光可以傳入構造函數的參數,還可以向特性的屬性賦值。在Obsolete的例子中,僅傳遞了構造函數的參數。構造參數又稱為位置參數(傳入順序必須與構造函數聲明時一致);屬性參數也叫做命名參數。
下面通過自定義特性進一步學習特性。
自定義特性
假設我們有這麼一個需求:創建或者更新一個類文件是需要說明這個類是什麼時候誰創建的,以後是誰更新的等,是不是想下面這樣在類上添加注釋:
這樣手動添加是可以記錄下來但是需要查看所有類型的更新記錄顯然就不適合了。帶著這麼一個懸念,我們先看看Obsolete特性的具體定義如下所示:
using System.Runtime.InteropServices; namespace System { // 摘要: // 標記不再使用的程序元素。無法繼承此類。 [Serializable] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ComVisible(true)] public sealed class ObsoleteAttribute : Attribute { // 摘要: // 使用默認屬性初始化 System.ObsoleteAttribute 類的新實例。 public ObsoleteAttribute(); // // 摘要: // 使用指定的變通方法消息初始化 System.ObsoleteAttribute 類的新實例。 // // 參數: // message: // 描述可選的變通方法的文本字符串。 public ObsoleteAttribute(string message); // // 摘要: // 使用變通方法消息和布爾值初始化 System.ObsoleteAttribute 類的新實例,該布爾值指示是否將使用已過時的元素視為錯誤。 // // 參數: // message: // 描述可選的變通方法的文本字符串。 // // error: // 指示是否將使用已過時的元素視為錯誤的布爾值。 public ObsoleteAttribute(string message, bool error); // 摘要: // 獲取指示編譯器是否將使用已過時的程序元素視為錯誤的布爾值。 // // 返回結果: // 如果將使用已過時的元素視為錯誤,則為 true;否則為 false。默認為 false。 public bool IsError { get; } // // 摘要: // 獲取變通方法消息,包括對可選程序元素的說明。 // // 返回結果: // 變通方法文本字符串。 public string Message { get; } } }
我們看到Obsolete特性在定義時繼承了Attribute(這是特性必需的),使用了Serializable、ComVisible和AttributeUsage這三個屬性。Serializable屬性表明類型支持序列化;ComVisible為 true,指示該托管類型(public 類型)對 COM 是可見的;AttributeUsage定義您自己的特性類時,可通過在特性類上放置 AttributeUsageAttribute 來控制特性類的使用方式。
通過上述的學習並根據前面的需求,我們自定義一個特性RecordAttribute,實現代碼如下所示:
//該特性可用於方法和類並且可以重復的特價到一個類型上 [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple = true)] public class RecordAttribute : Attribute { private string _recordType;//記錄類型:更新or創建 private string _author;//作者 private string _date;//日期 private string _comment;//備注 //構造函數 public RecordAttribute(string recordType, string author, string date) { _recordType = recordType; _author = author; _date = date; } //對於位置參數,通常只提供get訪問器 public string RecordType { get { return _recordType; }} public string Author { get { return _author; } } public string Date { get { return _date; } } //構建一個屬性,在特性中也叫做命名參數 public string Comment { get; set; } }
記錄類修改或者更新的特性創建好了,下面是使用示例:
[Record("更新", "鞠小軍", "2014.8.3", Comment = "添加ToString()方法")] [Record("更新", "鞠小軍", "2014.8.3")] [Record("創建","鞠小軍","2014.8.2")] public class Message { //此處具體實現略 public override string ToString() { return "添加了ToString()方法"; } }這樣就成功實現了上面的需求,Message類添加的Record屬性實際上作為元數據添加到了程序集中。
第一個問題,你可以參考我的另一個回答:zhidao.baidu.com/question/463506213.html。
第二個問題,答案是可以。例子,我明天早上補充給你。
你好,請區分特性(Attribute)和屬性(Property).
屬性就是面向對象思想裡所說的封裝在類裡面的數據字段.
C#特性可以應用於各種類型和成員之前。特性的最主要目的就是自描述。並且因為特性是可以由自己定制的,而不僅僅局限於.NET提供的那幾個現成的,因此給 C#程序開發帶來了相當大的靈活性和便利。另外,特性也是類。不同於其它類的是,特性都必須繼承自System.Attribute類,否則編譯器如何知道誰是特性誰是普通類呢。當編譯器檢測到一個類是特性的時候,它會識別出其中的信息並存放在元數據當中,僅此而已,編譯器並不關心特性說了些什麼,特性也不會對編譯器起到任何作用.