C#特性學習筆記
本筆記摘抄自:https://www.cnblogs.com/susufufu/p/6882498.html,記錄一下學習過程以備後續查用。
一、官方概述
特性提供功能強大的方法,用以將後設資料或宣告資訊與程式碼(程式集、型別、方法、屬性等)相關聯。 特性與程式實體關聯後,即可在執行時使用名
為“反射”的技術查詢特性。
特性,如Serializable,它其實就是一個類,定義方式跟類一樣,且所有特性都是直接或間接繼承自Attribute基類。
二、自定義一個特性
自定義一個特性PermissionAttribute:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class PermissionAttribute : Attribute //類名是特性的名稱
{
public string compNo; //命名引數
private string _popeId, _popeName;
public PermissionAttribute(string popeId,string popeName) //popeId、popeName為定位引數
{
compNo = "DB_TEST";
_popeId = popeId;
_popeName = popeName;
}
}
下面讓我們看看,如何建立一個自定義特性?
1)一個自定義特性類必須直接或間接繼承自System.Attribute特性類。
2)為該自定義特性類指定System.AttributeUsage特性,並指定限制引數(列舉System.AttributeTargets和可選的AllowMultiple、Inherited命名引數)。
AttributeUsage的命名引數:AllowMultiple表示是否允許多次使用在同一目標上、Inherited表示是否同時應用於派生型別或過載版本。
3)類名是特性的名稱。
4)建構函式的引數是自定義特性的定位引數(應用該特性時必須放在引數列表的最前面),也可以是無參建構函式(如[Serializable])。
5)任何公共的讀寫欄位或屬性都是可選的命名引數。
6)如果特性類包含一個屬性,則該屬性必須為讀寫屬性。
三、應用特性
示例程式碼如下:
[Permission("01_01","使用者資料",compNo ="DB_SYSTEM")]
public class Users
{
public Users()
{
}
public int AddUser(string userId,string userName)
{
return 1;
}
}
應用特性 [Permission("01_01","使用者資料",compNo ="DB_SYSTEM")] 其實是通過建構函式的呼叫來例項化一個特性類。
根據約定,所有特性名稱都以單詞“Attribute”結束,如可系列化標記特性Serializable,它的全稱為SerializableAttribute。在程式碼中使用特性時,不需要
指定Attribute字尾,如上面程式碼,只需用Permission即可代表PermissionAttribute特性。
四、關聯特性
利用反射的原理,關聯特性類與[vb.net教程](https://www.xin3721.com/eschool/VBNetxin3721/)
目標型別(反射:主要利用Type類的屬性和方法來獲得一個目標型別的型別資訊物件,然後根據該物件可以得到目標
型別的資訊,如它的欄位、屬性、方法名、類名java基礎
等,有了這些資訊,下一步就可以為所欲為了,可以還原該型別,即反系列化,甚至建立一個新型別)。
示例程式碼如下:
class Program
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class PermissionAttribute : Attribute //類名是特性的名稱
{
public string compNo; //命名引數
private string _popeId, _popeName;
public PermissionAttribute(string popeId,string popeName) //popeId、popeName為定位引數
{
compNo = "DB_TEST";
_popeId = popeId;
_popeName = popeName;
}
}
[Permission("01_01","使用者資料",compNo ="DB_SYSTEM")]
public class Users
{
public Users()
{
}
public int AddUser(string userId,string userName)
{
return 1;
}
}
static void Main(string[] args)
{
//1、判斷Users類定義時,是否應用了該特性?
if (typeof(Users).IsDefined(typeof(PermissionAttribute),false))
{
//2、獲得該特性物件,之後就可以訪問它的成員(後設資料)。
PermissionAttribute attribute = (PermissionAttribute)Attribute.GetCustomAttribute(typeof(Users), typeof(PermissionAttribute));
if(attribute.compNo == "DB_SYSTEM")
{
Console.WriteLine("Hello World.");
Console.Read();
}
}
}
}
執行結果如下:
當編譯器發現一個特性應用到一個目標併發生關聯時:
1)首先會把"Attribute"追加到[python基礎教程](https://www.xin3721.com/eschool/pythonxin3721/)
特性的名稱(若使用了簡寫),形成完整的特性類名。
2)然後在其所有引入的名稱空間中搜尋該特性類,若找不到該類或它與目標不匹配時,則產生編譯錯誤。
3)檢查傳遞給特性的引數,並查詢該特性中帶定位引數的建構函式(或無參建構函式)和其它可選的命名引數(特性類[c#教程](https://www.xin3721.com/eschool/CSharpxin3721/)的公共欄位、屬性),若找到匹配
的建構函式,則例項化該特性類,編譯器還會把目標型別的後設資料傳遞給程式集,反射可以從程式集中讀取後設資料,若找不到則產生編譯錯誤。
關聯程式碼也可以定義在目標型別的內部:
[Permission("01_01","使用者資料",compNo ="DB_SYSTEM")]
public class Users
{
public Users()
{
}
public int AddUser(string userId,string userName)
{
//1、判斷Users類定義時,是否應用了該特性?
if (typeof(Users).IsDefined(typeof(PermissionAttribute), false))
{
//2、獲得該特性物件,之後就可以訪問它的成員(後設資料)。
PermissionAttribute attribute = (PermissionAttribute)Attribute.GetCustomAttribute(typeof(Users), typeof(PermissionAttribute));
if (attribute.compNo == "DB_SYSTEM")
{
return 1;
}
}
return 0;
}
}
五、.NET預定義特性
至於.NET預定義特性的實現原理,我沒研究過,大概類似自定義特性吧,就比如系列化特性SerializableAttribute,實現原理我想大概是這樣:應用
[Serializable]時給目標做一個“標記”,在.NET內建程式集的某個地方判斷該目標型別是否應用了該特性,然後決定是否進行系列化操作。
相關文章
- C#學習筆記C#筆記
- c#學習筆記(一)C#筆記
- Go型別特性-學習筆記Go型別筆記
- JDK8 新特性學習筆記JDK筆記
- jdk-1.8新特性學習筆記JDK筆記
- NgRx Selector 的 Memoization 特性學習筆記筆記
- unity學習筆記-C#協程Unity筆記C#
- 我的C#學習筆記14C#筆記
- 我的C#學習筆記1C#筆記
- 學習筆記~1.4 HTML5新特性筆記HTML
- 精通C#學習筆記--C# 與 .NET平臺C#筆記
- C# 多執行緒學習筆記 – 1C#執行緒筆記
- 精通C#學習筆記---C#核心程式設計結構C#筆記程式設計
- [Java學習筆記]JDK1.8新特性學習(一)Lambda表示式Java筆記JDK
- MySQL 學習筆記(一)MySQL 事務的ACID特性MySql筆記
- JDK 新特性學習筆記之模組系統JDK筆記
- C#學習筆記-欄位、屬性、索引器C#筆記索引
- numpy的學習筆記\pandas學習筆記筆記
- Java學習筆記3事務的四大特性Java筆記
- C#學習筆記(補充)——擴充套件方法、事件C#筆記套件事件
- C#學習筆記-方法引數、擴充套件方法C#筆記套件
- C# 使用執行緒池佇列(學習筆記)C#執行緒佇列筆記
- C#設計模式學習筆記:設計原則C#設計模式筆記
- C#設計模式學習筆記:(9)組合模式C#設計模式筆記
- 學習筆記筆記
- python學習筆記-tip22(高階特性-列表生成式)Python筆記
- C#學習筆記之值型別與引用型別C#筆記型別
- C#關於List<T>的自定義排序學習筆記C#排序筆記
- C#學習日記4C#
- 【學習筆記】數學筆記
- ES6、ES7、ES8特性-學習筆記(一)筆記
- cocos2D-x初探學習筆記(31)2.1新特性CCPhysicsSprite筆記CSS
- 《JAVA學習指南》學習筆記Java筆記
- 機器學習學習筆記機器學習筆記
- C#學習筆記(與Java、C、C++和Python對比)C#筆記JavaC++Python
- C#學習筆記(六)——物件導向程式設計簡介C#筆記物件程式設計
- C#學習筆記---異常捕獲和變數運算子C#筆記變數
- 基於C#的內網穿透學習筆記(附原始碼)C#內網穿透筆記原始碼