C#特性
C#裏面有特性,屬性呀,很多面試題都會問,特性和屬性有啥區別,其實這兩個東西沒有啥關聯,只是名字帶有一個相同的字眼而已,稍微我會解釋我為啥這麽說,那麽今天我們先來學學特性。
(一) 什麽是特性
經常寫代碼的同學應該碰到過,這些特性[Serializable],[FormUri],[Obsolete],,,,特性給我們的感覺就是它貌似給我們的類或者方法,屬性字段,加多了一層處理邏輯一樣。其實我們的感覺沒有錯,特性就是在不破壞原來的結構上,封裝了額外的操作處理或流程。想想平時碰到的,用特性來做日誌處理,權限驗證,AOP是不是這個道理。下面我用圖的方式來告訴大家一些內容。
上圖是對我們C#程序運行的一個簡單介紹。
這幅圖主要說明了特性經過編譯器編譯後是存在程序集的元數據裏面的,如果你不對元數據進行操作,特性是不會起任何效果的。
(二)聲明和使用Attribute
特性:其實就是一個類,一個直接繼承或間接繼承自Attibute類。這個類的命名呢,一般是以Attribute結尾,但是在使用的時候,我們可以不寫後綴Attribute;
特性可以寫在屬性,方法,類,返回值。下面來看一個例子;
新建了一個叫User的類,裏面有四項Id,Name,Email,Tel;
static void Main(string[] args) { var userList = new List<User>(); userList.Add(new User() {Id=1,Name ="zhangzhen",Email ="[email protected]",Tel ="110"}); userList.Add(new User() { Id = 2, Name = "zhangzhen2", Email = "[email protected]", Tel = "110" }); userList.Add(new User() { Id = 3, Name = "zhangzhen3", Email = "[email protected]", Tel = "110" }); foreach (var u in userList){ Console.WriteLine($"Id={u.Id},Name={u.Name}"); } }
現在控制臺輸出是:
忽然有一天需求來了說,我不想要Id,我想要編號,名稱這種形式。那現在我就問問,大家應該怎麽做呢,A說:那把Id和Name改成編號,名稱這種形式了;B說:寫入資源文件裏面去;C說:用特性,得了,我們這裏用特性來實現(A和B的請各位客觀自己想想有啥不好的)。
那我們就用特性實現唄。
我們先定義了一個叫做ChineseNameAttribute,如下:
/// <summary> /// 自定義特性 /// </summary> public class ChineseNameAttribute:Attribute { private readonly string _chineseName; public ChineseNameAttribute(string chineseName) { this._chineseName = chineseName; } public string GetChineseName(){ return this._chineseName; } }
定義完了之後,啥也不說,馬上給剛剛的User類加上,
public class User { [ChineseName("用戶編號")] public int Id { get; set; } [ChineseName("用戶名稱")] public string Name { get; set; } [ChineseName("用戶郵箱")] public string Email { get; set; } [ChineseName("用戶電話")] public string Tel { get; set; } }
加好了,之後,我們馬上來看看效果。
在運行剛剛那段代碼,啥也沒有,啥也沒出來,我們不是添加了特性了嗎...噢噢噢噢,明白了原來特性經過編譯器編譯之後是存在程序集的元數據的,我們知道元數據對對我們程序集的一些清單,描述信息。那我們應該要怎麽讓特性取作用了,其實這個問題就是我們如何讓元數據來影響我們程序的運行呢---》這個就是典型的反射。
foreach (var u in userList) { var uType = u.GetType(); foreach (var item in uType.GetProperties()) { var attrArr = item.GetCustomAttributes(typeof(ChineseNameAttribute), false); //這裏返回的是一個數組 var attrName = item.Name; if (attrArr.Length > 0) { var chineseNameAttr = attrArr[0] as ChineseNameAttribute; attrName = chineseNameAttr.GetChineseName(); } Console.WriteLine($"{attrName}={item.GetValue(u)}"); } Console.WriteLine("********************"); }
版本2:調用方式
foreach (var u in userList) { var uType = u.GetType(); foreach (var item in uType.GetProperties()) { var attrName = item.Name; var ats = from a in item.GetCustomAttributes(typeof(ChineseNameAttribute), true) let a2 = a as ChineseNameAttribute where a2 != null select a2; foreach (var chineseName in ats) //因為這邊只有一項 attrName = chineseName.GetChineseName(); Console.WriteLine($"{attrName}={item.GetValue(u)}"); } }
上面就是讓我們特性生效的代碼。
講到這裏,我們知道了特性大概有啥作用,但是對於特性裏面的一些概念和定義還尚未涉及到,所以接下來的時候,講點特性的相關概念。
(三)特性的概念方面的東西介紹
[AttributeUsage(param)] ,是系統自帶的一個特性,用來用來指定當前特性用在哪裏,第一次看到這個東西,我們可能不會用,沒有關系,我們按照自己的思路來。
下面這個是AttributeUsage特性的源碼和中文意思,在VS的F12可以看到各個公開的屬性和方法。
通過源碼的閱讀和Vs裏面的一些中文說明,我們可以了解到特性的相關的概念,特性的作用對象是啥,特性是否可以被繼承,是否運行多重繼承(因為我相信很多同誌,估計都記不住這些概念的,但是我們可以按照上面的方法進行查找。
以上就是特性的簡單介紹,其實特性的東西遠不止這些...接下來會出更多關於這方面的文章,請大家留言討論。
C#特性