DAY 27 特性 特性
屬性提供以宣告方式將資訊與程式碼相關聯的方法。 它們也可提供可重複使用的元素,以套用至各種不同的目標。 屬性是繼承自 Attribute 基底類別的類別。 繼承自 Attribute 的任何類別都能在其他程式碼片段上做為一種「標記」。
Attribute 有人叫做屬性,也有人叫做特性,為了與 Property 區隔,本系列文就叫特性,雖然本人習慣上是叫屬性。
特性是將額外內容透過反射的方式給予目標,根據官方的解釋,目標有以下這些
Assembly
類別
建構函式
Delegate - 委派
列舉
Event - 事件
欄位
GenericParameter
介面
方法
Module
參數
屬性
ReturnValue
結構
簡單的示範一下特性的用法,並套用在我們的類別
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Member { public int ID { get ; set ; } [My (12) ] public string Name { get ; set ; } public void Print ( ) { Console.WriteLine ($"ID = {ID} , Name = {Name} " ); } } class MyAttribute : Attribute { public int Length { get ; set ; } public MyAttribute (int length ) { Length = length; } }
可以看到屬性 Name 上面多了 [My (12)],特性以 [] 括弧內容表示使用哪一個特性,並標住在目標上方。
在建立特性時,只要繼承 Attribute 即可當作特性,建議是加入 Attribute 當作名詞後綴,當你用這種方式取名,可以看到雖然特性名稱是 MyAttribute,但使用時可以省略 Attribute 字詞,當然也方便別人一眼就能認出你寫的就是特性。
如果只是單純的加特性,可以發現程式碼其實沒什麼變動,假如我們想要有一個來驗證屬性不大於 Length 的方法,如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class MyAttribute : Attribute { public int Length { get ; set ; } public MyAttribute (int length ) { Length = length; } public static bool IsValid (object obj, string prop ) { var property = obj.GetType ().GetProperty (prop); if (property is null ) return false ; var value = (object ) property.GetValue (obj, null ); if (value is null ) return false ; var attr = (MyAttribute) property.GetCustomAttribute (typeof (MyAttribute), false ); if (attr is null ) return false ; var length = attr.Length; return ((string ) value ).Length <= length; } }
請注意範例可能寫得不是很好,或者真實用法不是長這樣。
IsValid 方法就是
將參數的 obj 轉換成 Type 類型並且獲得與 prop 名稱一樣的屬性資訊 property,若無則傳回 false。
將 property 的值給予 value,若 value 為空則傳回 false。
在 property 的特性中取得名稱 MyAttribute 的特性 attr,若找不到符合特性則傳回 false。
比較特性 attr 中輸入的值,也就是 My (12) 的 12 是不是大於物件 obj 的屬性 prop 長度。
第三點中,因為特性不是只能有一個,但同特性只能有一個,所以在取特性時,也可以一次取出所有特性,GetCustomAttributes () 傳回的是陣列。
若要多個特性可以寫成
1 2 3 [My (12) ] [My2 (20) ] public string Name { get ; set ; }
或者是
1 2 [My (12), My2 (20) ] public string Name { get ; set ; }
再來就是使用這個驗證方法,如
1 2 3 4 5 6 7 8 9 10 11 var members = new List<Member> () { new Member () { ID = 0 , Name = "Mio" }, new Member () { ID = 1 , Name = "Miffy" }, new Member () { ID = 2 , Name = "Lulu" }, new Member () { ID = 3 , Name = "NekoSan" }, new Member () { ID = 3 , Name = "MooDoooooooooooooooooo" } }; foreach (var member in members) { Console.WriteLine ($"Name = {member.Name} , IsValid = {MyAttribute.IsValid (member, "Name" )} " ); }
特性的特性 有類別的類別,當然也有特性的特性囉,特性的特性可以限定特性使用在哪一個目標上,如
1 2 3 4 [AttributeUsage (AttributeTargets.Class) ] class MyAttribute : Attribute { }
可以看到瞬間出現紅字,只要多加AttributeTargets.Property
就可以在我們的屬性上使用了。
一些小結論 特性的使用可以把一些額外的資訊附加在目標上,例如我忘記在哪邊看到的程式碼維護程度,把特性當作一個 TAG,讓維護的人知道這裡有多大的坑,並無實際操作特性內容。
感謝閱讀,今天的內容可能有誤,閱讀後請再三求證喔。
參考資料屬性 - C# | Microsoft Docs C#屬性(Attribute)用法實例解析 - 掃文資訊