特性 特性(Attribute)是用於在運行時傳遞程式中各種元素(比如類、方法、結構、枚舉、組件等)的行為信息的聲明性標簽。 特性可以當成一個特殊的類看待 列舉特性語法: attribute為特性名稱,positional_parameters, name_parameter是特性屬性,value為 ...
特性
特性(Attribute)是用於在運行時傳遞程式中各種元素(比如類、方法、結構、枚舉、組件等)的行為信息的聲明性標簽。
特性可以當成一個特殊的類看待
列舉特性語法:
[attribute(positional_parameters, name_parameter = value, ...)]
element
attribute為特性名稱,positional_parameters, name_parameter是特性屬性,value為name_parameter屬性的值
三種預定義特性:
.Net Framework 提供了三種預定義的特性:
1. AttributeUsage
該特性描述了用戶定義的特性類如何被使用
AttributeUsage基本結構:
[AttributeUsage( validon,
AllowMultiple=allowmultiple,
Inherited=inherited )]
示例:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
validon規定了該特性能夠被承載,或者說是能夠被那些類型所使用的聲明,如示例中指明瞭該特性只能在Class(類),constructor(結構體),Field(欄位),Method(方法),Property(屬性)
AllowMutiple規定是否能被重覆使用,如果為true則能被重覆使用
Inherited規定這個特性是否能被派生類繼承,預設false不可繼承,true則為可繼承
2.Conditional
這個預定義特性標記了一個條件方法,其執行依賴於特定的預處理標識符
它會引起方法調用的條件編譯,取決於指定的值,比如 Debug 或 Trace。例如,當調試代碼時顯示變數的值
Conditional的基本結構:
[
Conditional(
conditionalSymbol
)]
使用示例:
#define hong using System; using System.Diagnostics; public class Myclass { [Conditional("hong")] //預定義的Conditional特性 public static void Message(string msg) { Console.WriteLine(msg); } } class Test { static void function1() { Myclass.Message("In Function 1."); function2(); } static void function2() { Myclass.Message("In Function 2."); } public static void Main() { Myclass.Message("In Main function."); function1(); } }
該程式預定義了一個巨集:hong,Conditional特性在函數Message中被使用:[Conditional("hong")] 如果沒有該巨集定義則不會執行函數Message
1. 若定義了巨集則程式如上,運行:(Message會被調用)
In Main function.
In Function 1.
In Function 2.
C:\C#\code\Conditional\bin\Debug\netcoreapp3.0\Conditional.exe (進程 18092)已退出,返回代碼為: 0。
若要在調試停止時自動關閉控制台,請啟用“工具”->“選項”->“調試”->“調試停止時自動關閉控制台”。
按任意鍵關閉此視窗...
2. 若將第一行定義巨集註釋:
//#define hong using System; using System.Diagnostics;
運行(此時Message函數不會被調用,則沒有輸出):
C:\C#\code\Conditional\bin\Debug\netcoreapp3.0\Conditional.exe (進程 18264)已退出,返回代碼為: 0。
若要在調試停止時自動關閉控制台,請啟用“工具”->“選項”->“調試”->“調試停止時自動關閉控制台”。
按任意鍵關閉此視窗...
3.Obsolete
這個預定義特性標記了不應被使用的程式實體。它可以讓您通知編譯器丟棄某個特定的目標元素。例如,當一個新方法被用在一個類中,但是您仍然想要保持類中的舊方法,您可以通過顯示一個應該使用新方法,而不是舊方法的消息,來把它標記為 obsolete(過時的)。
Obsolete特性結構:
[Obsolete(
message )]
[Obsolete(
message,
iserror )]
message:為描述文字,不使用該函數的原因以及替換函數
iserror:為bool值,true則編譯器會把引用了該特性的項目當成錯誤,產生編譯器警告
示例:
using System; public class MyClass { [Obsolete("Don't use OldMethod, use NewMethod instead", true)] static void OldMethod() { Console.WriteLine("It is the old method"); } static void NewMethod() { Console.WriteLine("It is the new method"); } public static void Main() { OldMethod(); } }
運行編譯器會提示錯誤:
Don't use OldMethod, use NewMethod instead
創建自定義特性的步驟:
- 聲明自定義特性
- 構建自定義特性
- 在目標程式元素上應用自定義特性
- 通過反射訪問特性
詳細示例在學習完反射後一同進行
反射
反射(Reflection) 對象用於在運行時獲取類型信息。該類位於 System.Reflection 命名空間中,可訪問一個正在運行的程式的元數據。
System.Reflection 命名空間包含了允許您獲取有關應用程式信息及嚮應用程式動態添加類型、值和對象的類。
反射(Reflection)有下列用途:
- 它允許在運行時查看屬性(attribute)信息。
- 它允許審查集合中的各種類型,以及實例化這些類型。
- 它允許延遲綁定的方法和屬性(property)。
- 它允許在運行時創建新類型,然後使用這些類型執行一些任務。
查看元數據
using System; [AttributeUsage(AttributeTargets.All)] //規定了特性的能承載所有類型 public class HelpAttribute : System.Attribute //自定義特性HelpAttribute繼承自Attribute基類 { public readonly string Url; public string Topic // Topic 是一個表示名字的參數 { get { return topic; } set { topic = value; } } public HelpAttribute(string url) // url 是一個表示位置的參數 { this.Url = url; } private string topic; } public class OtherAttribute : System.Attribute { public string topic2 { get { return topic2; } set { topic2 = value; } } } [HelpAttribute("Information on the class MyClass")] //特性被應用到MyClass一個空類中 [OtherAttribute()] //第二個特性 class MyClass { } namespace AttributeAppl { class Program { static void Main(string[] args) { System.Reflection.MemberInfo info = typeof(MyClass); //System.Reflection.MemberInfo初始化 object[] attributes = info.GetCustomAttributes(true); //獲取目標類(MyClass)所承載的特性 for (int i = 0; i < attributes.Length; i++) //遍歷所有特性 { System.Console.WriteLine(attributes[i]); } } } }
System.Reflection.MemberInfo info = typeof(MyClass);
System.Reflection.MemberInfo需要初始化,用於與目標類關聯(MyClass)
結果:(返回了MyClass類所承載的兩個特性)
HelpAttribute
OtherAttribute
C:\C#\code\Feflection\bin\Debug\netcoreapp3.0\Feflection.exe (進程 6244)已退出,返回代碼為: 0。
若要在調試停止時自動關閉控制台,請啟用“工具”->“選項”->“調試”->“調試停止時自動關閉控制台”。
按任意鍵關閉此視窗...
利用特性設置聲明信息並用反射進行訪問
using System; using System.Reflection; namespace attribute { [AttributeUsage(AttributeTargets.Class| //聲明自定義特性,描述自定義特性DebugInfo如何被使用 AttributeTargets.Constructor| AttributeTargets.Field| AttributeTargets.Method| AttributeTargets.Property, AllowMultiple =true)] public class DebugInfo : Attribute //構建自定義特性 { private int bugNo; //bug number private string developer; private string lastReview; //last reviewed public string message; public DebugInfo(int BN,string D,string LR) //構造函數 { this.bugNo = BN; this.developer = D; this.lastReview = LR; } public int BugNo { get { return bugNo; } } public string Developer { get { return developer; } } public string LastReview { get { return lastReview; } } public string Message { set { message = value; } get { return message; } } } [DebugInfo(45,"asahi","19/5/1",Message ="can't return type")] //在目標程式元素上應用自定義特性 [DebugInfo(50,"Lock","19/9/9",Message ="unable variable")] class Rectangle //矩形類,承載了兩個特性 { protected double length; protected double width; public Rectangle(double L,double W) { this.length = L; this.width = W; } [DebugInfo(55,"sayo","19/9/15",Message ="return false")] public double getArea() { return length * width; } [DebugInfo(60,"katsumi","19/10/1",Message ="output error")] public void Display() { Console.WriteLine("Length={0}", length); Console.WriteLine("Width={0}", width); Console.WriteLine("Area={0}", getArea()); } } class Program { static void Main(string[] args) { Rectangle r = new Rectangle(10, 5); r.Display(); Type type = typeof(Rectangle); //獲取Rectangle的類型 //遍歷Rectangle特性 Console.WriteLine(" Rectangle類型的特性測試:"); foreach(object attributes in type.GetCustomAttributes(false)) //獲取Rectangle類型的所有特性,迭代的方式賦予attributes { DebugInfo debugInfo = (DebugInfo)attributes; //所有特性轉換為DebugInfo類型 if (debugInfo != null) { Console.WriteLine("Debug number:{0}", debugInfo.BugNo); Console.WriteLine("Developer:{0}", debugInfo.Developer); Console.WriteLine("Last Review:{0}", debugInfo.LastReview); Console.WriteLine("Message:{0}\n", debugInfo.Message); } } Console.WriteLine(" Rectangle類型的所有函數的特性測試:"); //遍歷方法屬性 foreach(MethodInfo m in type.GetMethods()) //遍歷type類型即Rectangle類型所有函數 { foreach(object attributes in m.GetCustomAttributes(false)) //遍歷每個函數的特性 { DebugInfo debugInfo = (DebugInfo)attributes; if (debugInfo != null) { Console.WriteLine("Debug number:{0}", debugInfo.BugNo); Console.WriteLine("Developer:{0}", debugInfo.Developer); Console.WriteLine("Last Review:{0}", debugInfo.LastReview); Console.WriteLine("Message:{0}\n", debugInfo.Message); } } } } } }
結果:
Length=10 Width=5 Area=50 Rectangle類型的特性測試: Debug number:45 Developer:asahi Last Review:19/5/1 Message:can't return type Debug number:50 Developer:Lock Last Review:19/9/9 Message:unable variable Rectangle類型的所有函數的特性測試: Debug number:55 Developer:sayo Last Review:19/9/15 Message:return false Debug number:60 Developer:katsumi Last Review:19/10/1 Message:output error C:\Program Files\dotnet\dotnet.exe (進程 8772)已退出,返回代碼為: 0。 若要在調試停止時自動關閉控制台,請啟用“工具”->“選項”->“調試”->“調試停止時自動關閉控制台”。 按任意鍵關閉此視窗...
參考鏈接:
https://www.w3cschool.cn/wkcsharp/8jib1nvi.html
https://www.w3cschool.cn/wkcsharp/9phg1nvl.html