玩轉C#之【特性(attribute)】

閱讀時間約 1 分鐘

介紹

特性attribute,和注釋有什麼區別

第一個感受
特性:中括號宣告
錯覺:每一個特性都可以帶來對應的功能
實際上添加後,編譯器會在元素內部產生IL,但是我們是沒辦法直接使用的,而且在metadata會有紀錄
  • 特性會影響程式執行
  • 注釋不會影響程式執行
特性,本身是沒用的,程式執行的過程中,可以透過反射找到特性,在沒有破壞類型封裝前提下,可以加點額外的訊息和行為,任何一個可以生效的特性,都是因為有地方主動使用它的

特性的範例

//Api升級時,會在舊版本上面加上的特性,當編譯時會出現警告畫面
[Obsolete("請不要使用這個了,請使用什麼來代替",true)]//影響編譯器運行
//當Obsolete => true 編譯會直接報錯誤 false 編譯報警告

[Serializable]//可以序列化和反序列化 可以影響程式的運行
//MVC => filter ORM => table key display

實作一個特性

//定義:一個類別繼承Attribute 就是特性
//一般以Attribute結尾,宣告時可以省略掉
public class CustomAttribute:Attribute
{

}
[Custom]
public class Student
{
public int Id{get;set;}
public string Name{get;set;}
public void Study()
{
Console.WriteLine($"這裡是{this.Name}跟者老師學習");
}

public string Answer(string name)
{
return $"This is {name}";
}
}

宣告和使用attribute,AttributeUsage

AttributeTargets=>指定可以被哪個類型修飾
Inherited =true =>可不可以被繼承,默認是true
AllowMultiple =>多重修飾,默認是false,通常不推薦使用
[AttributeUsage(AttributeTargets.All,AllowMultiple = true)]=>讓宣告可以多重修飾某個元素
public class CustomAttribute:Attribute
{
public CustomAttribute()
{}

public CustomAttribute(int id)
{}

public string Description{get;set;}

public string Remark = null;

public void Show()
{
Console.WriteLine($"This is{nameof(CustomAttribute)}");
}
}
[Custom]   完全一樣的,表示都是使用無參數的建構子
[Custom()] 完全一樣的,表示都是使用無參數的建構子
[Custom(123)]帶參數的建構子
[Custom(123),Custom(123, Description ="123")] 多重修飾
[Custom(123, Description ="123",Remark ="2345")] //方法不行
public class Student
{
public int Id{get;set;}
public string Name{get;set;}
public void Study()
{
Console.WriteLine($"這裡是{this.Name}跟者老師學習");
}

[Custom] //方法加上特性
[return:Custom()] //給方法返回值加上特性
public string Answer([Custom] string name)//給參數也加上特性
{
return $"This is {name}";
}
}
使用反射找特性
public class Manager
{
public static void Show(Student student)
{
Type type =typeof(Student);//student.GetType();
if(type.IsDefined(typeof(CustomAttribute),true))//檢查有沒有 性能高
{
CustomAttribute attribute = (CustomAttribute)type.GetCustomAttribute(typeof(CustomAttribute),true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}

PropertyInfo propertyinfo = type.GetProperty("id");
if(propertyinfo.IsDefined(typeof(CustomAttribute),true))
{
CustomAttribute attribute = (CustomAttribute)propertyinfo.GetCustomAttribute(typeof(CustomAttribute),true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}

MethodInfo method = type.GetMethod("Answer");
if(method.IsDefined(typeof(CustomAttribute),true))
{
CustomAttribute attribute = (CustomAttribute)method.GetCustomAttribute(typeof(CustomAttribute),true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}

ParameterInfo parameter = method.GetParameters()[0]
if(parameter.IsDefined(typeof(CustomAttribute),true))
{
CustomAttribute attribute = (CustomAttribute)parameter.GetCustomAttribute(typeof(CustomAttribute),true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}

ParameterInfo Returnparameter = method.ReturnParameter;
if(Returnparameter.IsDefined(typeof(CustomAttribute),true))
{
CustomAttribute attribute = (CustomAttribute)Returnparameter.GetCustomAttribute(typeof(CustomAttribute),true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}


student.Study();
string result = student.Answer("Apple");
}
}

應用範例,增加訊息

public enum UserState
{
//正常
Normal = 0,
//凍結
Frozen = 1,
//刪除
Deleted =2
}
一般使用的情況
UserState userState = UserState.Normal;
if( userState == UserState.Normal)
{
Console.WriteLine("正常狀態");
}else if(userState == UserState.Frozen)
{
Console.WriteLine("凍結");
}
使用Attribute
public class RemarkAttribute:Attribute
{
public RemarkAttribute(string remark)
{
this._Remark = remark;
}
private string _Remark = null;
public string GetRemark()
{
return this._Remark;
}
}
//在列舉上加上一個描述,實體類的屬性也可以 Display=>已經有的
//別名 映射
public enum UserState
{
//正常
[Remark("正常")]
Normal = 0,
//凍結
[Remark("凍結")]
Frozen = 1,
//刪除
[Remark("刪除")]
Deleted =2
}
查找
public static class RemarkExtension
{
public static string GetRemark(this Enum value)
{
Type type = value.GetType();
FieldInfo field = type.GetField(value.ToString());
if(field.IsDefined(typeof(RemarkAttribute),true))
{
RemarkAttribute attribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute),true);
return attribute.GetRemark();
}else
{
return value.ToString();
}
}
}
UserState userState = UserState.Normal;
Console.WriteLine(userState.GetRemark());

應用範例,增加行為

public static class ValidateExtension
{
public static bool Validate(this object oObject)
{
Type type = oObject.GetType();
foreach(var prop in type.GetProperties())
{
if(prop.IsDefined(typeof(LongAttribute),true))
{
LongAttribute attribute = prop.GetCustomAttribute(typeof(LongAttribute),true);
if(!attribute.Validate(prop.GetValue(oObject)))
{
return false;
}
}
}
return true;
}
}
public class LongAttribute:Attribute
{
private long _Min =0;
private long _Max = 0;
public LongAttribute(long min,long max)
{
_Min = min;
_Max=max;
}

public bool Validate(object value)
{
if(value != null && string.IsNullOrWhiteSpace(value.ToString()))
{
if(long.TryParse(value.ToString(),out long lResult))
{
if(lResult > this._Min&& lResult <this._Max)
{
return true;
}
}
}
return false;

}
}
public class Student
{
public int Id{get;set;}
//可以做長度檢查的特性
public string Name{get;set;}
//範圍10001~999999999999
[LongAttribute(10001,999999999999)]
public long QQ{get;set;}
public void Study()
{
Console.WriteLine($"這裡是{this.Name}跟者老師學習");
}

[Custom] //方法加上特性
[return:Custom()] //給方法返回值加上特性
public string Answer([Custom] string name)//給參數也加上特性
{
return $"This is {name}";
}
}
public class Manager
{
public static void Show(Student student)
{
Type type =typeof(Student);//student.GetType();
if(type.IsDefined(typeof(CustomAttribute),true))//檢查有沒有 性能高
{
CustomAttribute attribute = (CustomAttribute)type.GetCustomAttribute(typeof(CustomAttribute),true);
Console.WriteLine($"{attribute.Description}_{attribute.Remark}");
attribute.Show();
}

//數值檢查 範圍10001~999999999999

//一般寫法
if(student.QQ > 10001 & sudent.QQ <999999999999)
{

}else
{

}
//使用Attribute
student.Validate();

student.Study();
string result = student.Answer("Apple");
}
}

參考資料

本篇已同步發表至個人部落格
https://moushih.com/2022ithome09/
鐵人賽文章
https://ithelp.ithome.com.tw/articles/10288837
為什麼會看到廣告
8會員
39內容數
我是這個部落格的作者,喜歡分享有關投資 💰、軟體開發 💻、占卜 🔮 和虛擬貨幣 🚀 的知識和經驗。
留言0
查看全部
發表第一個留言支持創作者!
一代軍師 的其他內容
介紹 反射:System.Reflection .Net框架提供的Library,可以讀取並使用metadata Dll-IL-Metadata-反射 透過VS編譯器 編譯成dll/exe 點擊exe的時候,他有一個依賴的環境叫做CLR IL:可以透過ILSpy(反編譯工具) 📷 一般情況
介紹 在C#2.0時代以前,是沒有泛型的,所以當我們遇到需求是方法內做相同的事情,但因為輸入或輸出的型別不一樣,我們就必須重複寫出類似的程式 以下的例子是=>不同的輸入型別 但卻做相同的事情 =>印出輸入資料 範例: 輸入參數:int或string或DateTime 功能:印出輸入的"數值"
介紹 分層架構模式,是將一個軟體系統進行分層,每個軟體系統都去要通過層來隔離不同的關注點,其中最為經典的就是三層架構以及領域驅動設計提出的四層架構。 📷 三層式架構 下面會介紹每一層專門要處理的事情 最常是用的分層方式 至於每層模組的命名方式,每間公司都不太ㄧ樣 📷 參考資料 鐵人賽文章
介紹 類似Windows排程的一個套件,不過他有Dashboard可以看 可以用在商業用途 使用情境 簡單來說如果你需要定時的執行某一段程式就可以使用這個套件來幫你完成。 優點 Simple 開發簡易、安裝簡單、方便部署 Persistent 工作任務可存放於多種儲存裝置 任務執行方式 版本 📷
Swagger是SmartBear Software的API開發人員套件工具,它是OpenAPI規範的基礎規範。 簡單來說就是 API 文件產生器。
在上一篇文章介紹過API之後,大家應該會很好奇寫好了一隻API應該怎麼測試巴?
介紹 反射:System.Reflection .Net框架提供的Library,可以讀取並使用metadata Dll-IL-Metadata-反射 透過VS編譯器 編譯成dll/exe 點擊exe的時候,他有一個依賴的環境叫做CLR IL:可以透過ILSpy(反編譯工具) 📷 一般情況
介紹 在C#2.0時代以前,是沒有泛型的,所以當我們遇到需求是方法內做相同的事情,但因為輸入或輸出的型別不一樣,我們就必須重複寫出類似的程式 以下的例子是=>不同的輸入型別 但卻做相同的事情 =>印出輸入資料 範例: 輸入參數:int或string或DateTime 功能:印出輸入的"數值"
介紹 分層架構模式,是將一個軟體系統進行分層,每個軟體系統都去要通過層來隔離不同的關注點,其中最為經典的就是三層架構以及領域驅動設計提出的四層架構。 📷 三層式架構 下面會介紹每一層專門要處理的事情 最常是用的分層方式 至於每層模組的命名方式,每間公司都不太ㄧ樣 📷 參考資料 鐵人賽文章
介紹 類似Windows排程的一個套件,不過他有Dashboard可以看 可以用在商業用途 使用情境 簡單來說如果你需要定時的執行某一段程式就可以使用這個套件來幫你完成。 優點 Simple 開發簡易、安裝簡單、方便部署 Persistent 工作任務可存放於多種儲存裝置 任務執行方式 版本 📷
Swagger是SmartBear Software的API開發人員套件工具,它是OpenAPI規範的基礎規範。 簡單來說就是 API 文件產生器。
在上一篇文章介紹過API之後,大家應該會很好奇寫好了一隻API應該怎麼測試巴?
你可能也想看
Thumbnail
作家 Morgan Housel 在《華爾街日報》中提出一個觀點:我們是用理解知識的方式在思考、學習金錢觀,而不是用理解心智與行為模式的方式學習理財。這段話讓我意識到,我們的財務決策並非總是理性的,情緒因素也扮演著重要角色。通過掌握金錢心理學,能夠幫助我們改善用錢習慣,使財務決策更為理性和長遠。
Thumbnail
進入物件導向設計的實戰階段,我們通過建立人力資源管理功能來實踐理論知識。透過這些實作練習,能夠深化對物件導向概念的理解,並學會如何在實際開發中應用這些概念。
Thumbnail
在物件導向程式設計的進階階段,學生將學習繼承、介面、抽象類別等核心概念。繼承允許類別共享屬性和方法,介面確保實現類別提供特定的方法實現,而抽象類別定義了基本結構供子類別擴展。這些知識點有助於提升程式碼的重用性、擴展性和維護性。
Thumbnail
暢銷懸疑小說的《法庭遊戲》改編為電影版,日前也在台灣上映,燒腦的情節加上法庭的諜對諜攻防;再加上永瀨廉、杉咲花、北村匠海三位高人氣演員加持。
Thumbnail
自2020年問世以來,日本潮流品牌Water The Plant便以其獨特的設計理念和色彩豐富的產品系列,在全球潮流文化中掀起了一股正能量的旋風。
Thumbnail
戴姆勒克萊斯勒出產的後輪驅動雙門跑車 Chrysler Crossfire(火線),使用 33% 賓士 SLK 跑車零件,在 2003 年推出,於 2007 年因為公司重組後停產。雖然,1:1 的新車買不起,那買台 1:18 的模型車來玩玩總是可以的。😜
Thumbnail
透過美圖秀秀APP「AI 繪畫藝術」測試版,你會發現龍虎塔的塔,你會發現龍虎塔的塔型,變得更古色古香,有些還幻化成了日本建築風格,塔前的石橋被東方風格的街頭古燈所取代,潭前的荷花池全轉換成荷花池全轉換成了日式的庭園與石階,與西式的建築與路燈,上面還被白雪覆蓋著,連塔邊的樹種,天際的背景也有了轉換,東
Thumbnail
每年各種APP都會推出各種免費的年節電子賀卡,有的免費有的要付費,耶誕節、台灣元旦新年、農曆過年與西洋情人節陸續將至,如果你有寄發電子賀卡的習慣,今年不妨試試以下推薦的新玩意--- 免費的「美圖秀秀APP 「AI 繪畫藝術」多種畫風一鍵生成」!
Thumbnail
在餐桌上,時不時喜歡做些新鮮的嘗試,不管是食材的搭配或是烹調的方法,又或是餐桌(就是道具很多啦)的形式,菜色的嘗試往往都來自於看到臉友PO的美食照,或者是自己在外面用餐時看到的擺盤與菜餚,本以為這些嘗試的最大樂趣是複製成功,但後來發現真正有趣的是過程中的摸索。
Thumbnail
C_29 / 'Optimist' 的整體空間是由雅典知名的 314 architecture studio 所打造,創立者 Pavlo Hatjiaggelide 的背景是一名專業的土木工程師,擅長架構設計和室內設計,其設計作品就像是高純度的藝術品。
Thumbnail
相比起Celsius每週派息一次,NEXO的好處就是它會每天派息一次,只要在每天07:00-08:00 CET時區前存入資金便可以開始計算利息,如果過了這個時段才存入資金的話,便可能要等24小時以上才能獲得利息了XD。 b. 填寫你的 Email 和密碼 【個人網站】 【加密貨幣】 【被動收入】
Thumbnail
作家 Morgan Housel 在《華爾街日報》中提出一個觀點:我們是用理解知識的方式在思考、學習金錢觀,而不是用理解心智與行為模式的方式學習理財。這段話讓我意識到,我們的財務決策並非總是理性的,情緒因素也扮演著重要角色。通過掌握金錢心理學,能夠幫助我們改善用錢習慣,使財務決策更為理性和長遠。
Thumbnail
進入物件導向設計的實戰階段,我們通過建立人力資源管理功能來實踐理論知識。透過這些實作練習,能夠深化對物件導向概念的理解,並學會如何在實際開發中應用這些概念。
Thumbnail
在物件導向程式設計的進階階段,學生將學習繼承、介面、抽象類別等核心概念。繼承允許類別共享屬性和方法,介面確保實現類別提供特定的方法實現,而抽象類別定義了基本結構供子類別擴展。這些知識點有助於提升程式碼的重用性、擴展性和維護性。
Thumbnail
暢銷懸疑小說的《法庭遊戲》改編為電影版,日前也在台灣上映,燒腦的情節加上法庭的諜對諜攻防;再加上永瀨廉、杉咲花、北村匠海三位高人氣演員加持。
Thumbnail
自2020年問世以來,日本潮流品牌Water The Plant便以其獨特的設計理念和色彩豐富的產品系列,在全球潮流文化中掀起了一股正能量的旋風。
Thumbnail
戴姆勒克萊斯勒出產的後輪驅動雙門跑車 Chrysler Crossfire(火線),使用 33% 賓士 SLK 跑車零件,在 2003 年推出,於 2007 年因為公司重組後停產。雖然,1:1 的新車買不起,那買台 1:18 的模型車來玩玩總是可以的。😜
Thumbnail
透過美圖秀秀APP「AI 繪畫藝術」測試版,你會發現龍虎塔的塔,你會發現龍虎塔的塔型,變得更古色古香,有些還幻化成了日本建築風格,塔前的石橋被東方風格的街頭古燈所取代,潭前的荷花池全轉換成荷花池全轉換成了日式的庭園與石階,與西式的建築與路燈,上面還被白雪覆蓋著,連塔邊的樹種,天際的背景也有了轉換,東
Thumbnail
每年各種APP都會推出各種免費的年節電子賀卡,有的免費有的要付費,耶誕節、台灣元旦新年、農曆過年與西洋情人節陸續將至,如果你有寄發電子賀卡的習慣,今年不妨試試以下推薦的新玩意--- 免費的「美圖秀秀APP 「AI 繪畫藝術」多種畫風一鍵生成」!
Thumbnail
在餐桌上,時不時喜歡做些新鮮的嘗試,不管是食材的搭配或是烹調的方法,又或是餐桌(就是道具很多啦)的形式,菜色的嘗試往往都來自於看到臉友PO的美食照,或者是自己在外面用餐時看到的擺盤與菜餚,本以為這些嘗試的最大樂趣是複製成功,但後來發現真正有趣的是過程中的摸索。
Thumbnail
C_29 / 'Optimist' 的整體空間是由雅典知名的 314 architecture studio 所打造,創立者 Pavlo Hatjiaggelide 的背景是一名專業的土木工程師,擅長架構設計和室內設計,其設計作品就像是高純度的藝術品。
Thumbnail
相比起Celsius每週派息一次,NEXO的好處就是它會每天派息一次,只要在每天07:00-08:00 CET時區前存入資金便可以開始計算利息,如果過了這個時段才存入資金的話,便可能要等24小時以上才能獲得利息了XD。 b. 填寫你的 Email 和密碼 【個人網站】 【加密貨幣】 【被動收入】