屬性提供以宣告方式將資訊與程式碼相關聯的方法。
它們也可提供可重複使用的元素,以套用至各種不同的目標。
屬性是繼承自 Attribute 基底類別的類別。
繼承自 Attribute 的任何類別都能在其他程式碼片段上做為一種「標記」。
Attribute 有人叫做屬性,也有人叫做特性,為了與 Property 區隔,本系列文就叫特性,雖然本人習慣上是叫屬性。
特性是將額外內容透過反射的方式給予目標,根據官方的解釋,目標有以下這些
簡單的示範一下特性的用法,並套用在我們的類別
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 的方法,如
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 () 傳回的是陣列。
若要多個特性可以寫成
[My (12)]
[My2 (20)]
public string Name { get; set; }
或者是
[My (12), My2 (20)]
public string Name { get; set; }
再來就是使用這個驗證方法,如
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")}");
}
有類別的類別,當然也有特性的特性囉,特性的特性可以限定特性使用在哪一個目標上,如
[AttributeUsage (AttributeTargets.Class)]
class MyAttribute : Attribute {
//...
}
可以看到瞬間出現紅字,只要多加AttributeTargets.Property
就可以在我們的屬性上使用了。
特性的使用可以把一些額外的資訊附加在目標上,例如我忘記在哪邊看到的程式碼維護程度,把特性當作一個 TAG,讓維護的人知道這裡有多大的坑,並無實際操作特性內容。
感謝閱讀,今天的內容可能有誤,閱讀後請再三求證喔。
參考資料
屬性 - C# | Microsoft Docs
C#屬性(Attribute)用法實例解析 - 掃文資訊