建立一個可以讀寫自定義屬性(Attribute)列舉(Enum)的擴充方法
之前的文章(Enumeration(Enum)列舉型別之可用性增強)有介紹過,Enum可以透過System.ComponentModel.Description來定義一個延伸的字串屬性,讓你可以擴充紀錄(描述)一些你想要描述的事物,但有時候我們要的不只是這些而已,甚至想要使用一些自定義的型別來表述資料,這篇文章就是在教你怎麼將其實作出來。
Step 1. 創造一個自定義的屬性類別
public class IdAttribute : System.Attribute
{
public string cId { get; private set; }
public IdAttribute(string cTemp)
{ cId = cTemp; }
}
Step 2. 建立一個示範用的列舉,並將自定義的屬性加入。(在這裡為了延伸之前文章中介紹的擴充方法,因此也將System.ComponentModel.Description的寫法一併加入以利測試)
public enum People
{
[System.ComponentModel.Description("王約翰"), Id("A123456789")]
John = 0,
[System.ComponentModel.Description("陳瑪莉")]
Marry = 1,
Tom = 2,
Sherry = 4
}
Step 3. 把之前文章使用的擴充方法,拿來修改成新的泛型取用版本。
using System.Linq;
namespace Hello.ExtensionMethod
{
//相容之前的Description擴充方法取用名稱
public static string ToExtensionString(this System.Enum oTemp)
{
try
{ return oTemp.GetAttribute<System.ComponentModel.DescriptionAttribute>().Description; }
catch
{ return oTemp.ToString(); }
}
//泛型版本的屬性取用擴充方法
public static T GetAttribute<T>(this System.Enum oTemp) where T : System.Attribute
{
var oType = oTemp.GetType();
var cName = System.Enum.GetName(oType, oTemp);
var TResult = oType.GetField(cName).GetCustomAttributes(false).OfType<T>().SingleOrDefault();
if (TResult == null)
{ throw new System.Exception($"取出列舉屬性值的過程出現錯誤,請確定指定的屬性是否存在?"); }
return TResult;
}
}
從Enum取出自定義類別的值
廢話不多說,先看程式碼。
<%@ Import Namespace="Hello.ExtensionMethod" %>
protected void Page_Load(object sender, EventArgs e)
{
//狀況A
Response.Write($"<p>{People.John.ToExtensionString()}</p>");
//狀況B
Response.Write($"<p>{People.John.GetAttribute<IdAttribute>().cId}</p>");
//狀況C
Response.Write($"<p>{People.Marry.ToExtensionString()}</p>");
//狀況D
Response.Write($"<p>{People.Tom.ToExtensionString()}</p>");
//狀況E
try
{ Response.Write($"<p>{People.Sherry.GetAttribute<IdAttribute>().cId}</p>"); }
catch (Exception oEx)
{ Response.Write($"<p>{oEx.Message}</p>"); }
}
接著是說明:
- 狀況A:輸出「王約翰」,這不用多說。
- 狀況B:輸出「A123456789」,這不用多說。
- 狀況C:輸出「陳瑪莉」,這行單純只是要展示Attribute可以0~多個。
- 狀況D:輸出「Tom」,理論上Tom列舉並沒有設定System.ComponentModel.Description,但因為ToExtensionString我們有進行錯誤捕捉,當取Attribute發生錯誤時,程式碼會選擇把enum轉字串丟出,所以會丟出列舉本身的名稱,亦即為Tom。
- 狀況E:輸出「取出列舉屬性值的過程出現錯誤,請確定指定的屬性是否存在?」,我們Sherry列舉裡面根本沒有設定任何屬性,而卻要進行自定義屬性的取出,因此最終的結果是null,而程式碼中有進行簡單的檢查,當為null時候就拋出Exception,所以自然就是這個文字輸出了。
※ 值得一提的是,若在GetAttribute擴充方法中不進行null的檢查,直接回傳T泛型型別預設值是沒問題的(不會出現錯誤),但錯誤點會發生在最終的應用端。試想:如果People.Sherry.GetAttribute()是null,那麼你竟然要去對這個null調用其null.cId屬性?(這會觸發NullReferenceException!)
相關文章:Enumeration(Enum)列舉型別之可用性增強