C# 特性(Attribute)超詳細教程

文章目錄

  • 0.前篇
  • 1.特性概念
  • 2.特性的聲明和使用
    • 2.1 特性定義語法
    • 2.2 特性目標
  • 3.預定義特性
    • 3.1 AttributeUsage
    • 3.2 Conditional
    • 3.3 其它預定義特性
  • 4.MyAttributeHelper(特性使用幫助類)
  • 5.特性應用
    • 5.1 添加說明信息并獲取
    • 5.2 數據驗證

0.前篇

學習本文前建議先閱讀我的關于反射的博文:
https://editor.csdn.net/md/?articleId=139095147

1.特性概念

特性是用于在運行時傳遞程序中各種元素(比如類、方法、結構、枚舉、組件等)的行為信息的聲明性標簽。

2.特性的聲明和使用

2.1 特性定義語法

特性在聲明時以Attribute結尾,在使用時可省去Attribute

[attribute(positional_parameters, name_parameter = value,)]
element

參數說明:

  • positional_parameters: 表示特性必須具備的信息。
  • name_paramete:表示特性可選的信息。
  • element: 在這里表示特性目標。

代碼示例:
特性聲明:

public class TestAttribute : Attribute
{public int Parm { get; set; }private int id;private string name;public TestAttribute(){}public TestAttribute(int id, string name){this.id = id;this.name = name;}
}

特性使用:

[Test]  // 使用無參構造函數
public class TestClass1
{}[Test(Parm = 123)]  // 使用無參構造函數 + 指定參數
public class TestClass2
{}[Test(1, "test")]   // 使用有參構造函數
public class TestClass3
{}

2.2 特性目標

特性目標指的是應用特性的實體。例如,特性目標可以是類、特定方法或整個程序集。一般情況,特性應用于緊跟在它后面的元素。不過,C# 特性支持顯示標識,例如可以顯示標識為將特性應用于方法,或者是應用于其參數或返回值。

顯示標識特性目標的語法如下:

[target : attribute-list]
  • target:表示指定的特性目標值。
  • attribute-list:表示要應用的特性列表。

下表展示常用的 target 值:

目標值適用對象
assembly整個程序集
module當前程序集模塊
field類或結構中的字段
event事件
method方法或 get 和 set 屬性訪問器
param方法參數或 set 屬性訪問器參數
propertyProperty(屬性)
return方法、屬性索引器或 get 屬性訪問器的返回值
type結構、類、接口、枚舉或委托

代碼示例:

// 默認: 應用于方法
[Test]
int Method1()
{ return 0; 
}// 顯示指定應用于方法
[method: Test]
int Method2()
{ return 0; 
}// 應用于參數
int Method3([Test] string contract) 
{ return 0; 
}// 應用于返回值
[return: Test]
int Method4()
{ return 0; 
}

3.預定義特性

3.1 AttributeUsage

特性 AttributeUsage 描述了如何使用一個自定義特性類。注意,使用特性修飾的類 AttributeUsage 必須是 System.Attribute 的直接或間接派生類,否則將發生編譯時錯誤

AttributeUsage 特性的語法如下:

[AttributeUsage(validon, AllowMultiple = allowmultiple, Inherited = inherited)]
  • validon: 表示可被應用的特性目標值。它是枚舉器 AttributeTargets 的值的組合。默認值是 AttributeTargets.All。
  • AllowMultiple: 可選,allowmultiple 選項為其提供一個布爾值。表示特性是否能被重復放置多次
  • Inherited:可選,inherited 選項為其提供一個布爾值。表示 能否被派生類所繼承。

示例代碼:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class ExampleAttribute : Attribute
{public ExampleAttribute(string name){}
}

3.2 Conditional

特性 Conditional 是有條件的意思。使用特性修飾的方法也就是條件方法,條件方法的執行依賴于指定的預處理標識符。預處理標識符影響著方法調用的條件編譯,這種影響取決于指定的值。例如事先用預處理器指令定義了一個 Test 字符,當條件方法指定的值也為 Test 時, 則該方法會被執行。

語法:

[Conditional(conditionalSymbol)]
  • 參數 conditionalSymbol 表示指定的預處理標識符。
#define Test
using System;public class Example
{[Conditional("Test")]static void Method1(){Console.WriteLine("Method1");}static void Method2(){Console.WriteLine("Method2");}static void Main(){Method1();Method2();}
}

輸出:

Method1
Method2

注釋掉 #define Test 輸出

Method2

3.3 其它預定義特性

特性說明
[Obsolete]標記已過時的代碼,使得在使用過時成員時發出警告或錯誤信息。
[Serializable]用于標記類,表示該類可以序列化,即可以在網絡上傳輸或者在文件中存儲。
[DllImport]用于指示要在程序中調用非托管代碼(通常是 DLL)的方法。
[Conditional]與預處理指令 ‘#if’ 和 ‘#endif’ 結合使用,根據定義的條件編譯代碼。
[AttributeUsage]用于指定自定義特性的使用方式,如允許的目標類型和是否允許多次應用等。
[Conditional]根據條件編譯代碼,類似于預處理指令,但是使用 Attribute。
[DefaultValue]為屬性或字段設置默認值。
[Description]為屬性或者事件提供一個描述,通常在設計時使用。

4.MyAttributeHelper(特性使用幫助類)

using System.Reflection;namespace Ming.Utils
{public static class MyAttributeHelper{/// <summary>/// 獲取該類型下所有的帶Attribute的方法/// </summary>/// <typeparam name="T">特性類型</typeparam>/// <param name="type"></param>/// <returns></returns>public static List<MethodInfo> GetAllMethods<T>(Type type) where T : class, new(){var res = new List<MethodInfo>();res = type.GetMethods().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();return res;}/// <summary>/// 獲取該類型下所有的帶Attribute的屬性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<PropertyInfo> GetAllPropertys<T>(Type type) where T : class, new(){var res = new List<PropertyInfo>();res = type.GetProperties().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();return res;}/// <summary>/// 獲取程序集所有帶 T 特性的類class/// </summary>/// <typeparam name="T">特性類型</typeparam>/// <returns>程序集下所有帶 T 特性的類class</returns>public static List<Type> GetAllTypes<T>() where T : Attribute{var res = new List<Type>();//Assembly存放所有的程序集res = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我們找到所有程序集中帶有T特性的Type類型.ToList();return res;}/// <summary>/// 獲取類上的特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(Type type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 獲取方法上的特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(MethodInfo type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 獲取屬性上的特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(PropertyInfo type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 返回帶有Attribute的類型元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <returns></returns>public static List<(Type type, Att att)> GetAll_TypeAndAtt<Att>() where Att : Attribute, new(){var res = new List<(Type type, Att att)> ();var typeLists = GetAllTypes<Att>();foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));   }return res;}/// <summary>/// 返回帶有Attribute的變量元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<(PropertyInfo property, Att att)> GetAll_PropertyAndAtt<Att>(Type type) where Att : Attribute, new(){var res = new List<(PropertyInfo type, Att att)>();var typeLists = GetAllPropertys<Att>(type);foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));}return res;}/// <summary>/// 返回帶有Attribute的方法元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<(MethodInfo method, Att att)> GetAll_MethodAndAtt<Att>(Type type) where Att : Attribute, new(){var res = new List<(MethodInfo type, Att att)>();var typeLists = GetAllMethods<Att>(type);foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));}return res;}}
}

5.特性應用

5.1 添加說明信息并獲取

/// <summary>
/// 備注特性
/// </summary>
public class RemarkAttribute : Attribute
{private string Remark { get; set; }public RemarkAttribute(string Remark){this.Remark = Remark;}public string GetRemark(){return this.Remark;}
}// 枚舉
public enum ESex
{[Remark("男")]male = 1,[Remark("女")]female = 2,
}/// <summary>
/// Enum擴展方法
/// </summary>
public static class EnumExtension
{public static string GetRemark(this Enum model){if (model is ESex){Type type = typeof(ESex);FieldInfo fi = type.GetField(model.ToString());object[] attributes = fi.GetCustomAttributes(true);foreach (var attr in attributes){if (attr is RemarkAttribute){RemarkAttribute remark = (RemarkAttribute)attr;return remark.GetRemark();}}}return string.Empty;}
}

使用:

Console.WriteLine(ESex.male.GetRemark());
// 男

5.2 數據驗證

可參考:
https://www.cnblogs.com/jiangxifanzhouyudu/p/11107734.html
(1)基類抽象特性

using System;namespace MyAttribute.ValidateExtend
{public abstract class AbstractValidateAttribute : Attribute{public abstract bool Validate(object oValue);}
}

(2)子類特性實現–數字長度

using System;namespace MyAttribute.ValidateExtend
{[AttributeUsage(AttributeTargets.Property)]public class LongAttribute : AbstractValidateAttribute{private long _Min = 0;private long _Max = 0;public LongAttribute(long min, long max){this._Min = min;this._Max = max;}public override bool Validate(object oValue){return oValue != null&& long.TryParse(oValue.ToString(), out long lValue)&& lValue >= this._Min&& lValue <= this._Max;}}
}

(3)子類特性實現–可空

namespace MyAttribute.ValidateExtend
{public class RequiredAttribute : AbstractValidateAttribute{public override bool Validate(object oValue){return oValue != null&& !string.IsNullOrWhiteSpace(oValue.ToString());}}
}

(4)子類特性實現–字符串長度

using System;namespace MyAttribute.ValidateExtend
{[AttributeUsage(AttributeTargets.Property)]public class StringLengthAttribute : AbstractValidateAttribute{private int _Min = 0;private int _Max = 0;public StringLengthAttribute(int min, int max){this._Min = min;this._Max = max;}public override bool Validate(object oValue){return oValue != null&& oValue.ToString().Length >= this._Min&& oValue.ToString().Length <= this._Max;}}
}

(5)泛型擴展方法

using System;namespace MyAttribute.ValidateExtend
{public static class AttributeExtend{public static bool Validate<T>(this T t){Type type = t.GetType();foreach (var prop in type.GetProperties()){if (prop.IsDefined(typeof(AbstractValidateAttribute), true)){object oValue = prop.GetValue(t);foreach (AbstractValidateAttribute attribute in prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true)){if (!attribute.Validate(oValue))return false;}}}return true;}}
}

(6)常規類字段定義

using System;namespace MyAttribute.ValidateExtend
{public static class AttributeExtend{public static bool Validate<T>(this T t){Type type = t.GetType();foreach (var prop in type.GetProperties()){if (prop.IsDefined(typeof(AbstractValidateAttribute), true)){object oValue = prop.GetValue(t);foreach (AbstractValidateAttribute attribute in prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true)){if (!attribute.Validate(oValue))return false;}}}return tue;}}
}

(7)類調用擴展方法驗證字段

using MyAttribute.EnumExtend;
using MyAttribute.ValidateExtend;
using System;namespace MyAttribute
{/// <summary>/// main方法調用/// </summary>class Program{static void Main(string[] args){try{                #region 特性實現數據驗證,并且可擴展{//通過特性去提供額外行為//數據驗證--到處都需要驗證StudentVip student = new StudentVip(){Id = 123,Name = "無為",QQ = 729220650,Salary = 1010000};                    if (student.Validate()){Console.WriteLine("特性校驗成功");}//1 可以校驗多個屬性//2 支持多重校驗//3 支持規則的隨意擴展}#endregion}catch (Exception ex){Console.WriteLine(ex.Message);}Console.Read();}}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/15010.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/15010.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/15010.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

聊聊Python中的文件讀寫操作

Python 中的文件讀寫操作是數據處理和存儲的基本操作之一。下面&#xff0c;我將詳細解釋如何在 Python 中進行文件的讀寫操作。 1. 打開文件 在 Python 中&#xff0c;使用 open() 函數來打開文件。這個函數需要至少一個參數&#xff0c;即文件名&#xff0c;并且返回一個文件…

數據結構和組成

數據結構組成 數據項&#xff1a;一個數據元素可以由若干數據項組成。 數據對象&#xff1a;有相同性質的數據元素的集合&#xff0c;是數據的子集。 數據結構&#xff1a;是相互之間存在一種或多種特定關系的數據元素的集合。 邏輯結構 數據對象中數據元素之間的相互關系 eg: …

深入理解python列表遍歷:兩種方法詳解與實例

新書上架~&#x1f447;全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目錄 一、引言 二、使用索引遍歷列表 三、直接使用元素遍歷列表 四、總結 一、引言 在編程過程…

創建python字典的兩種方法:直觀與函數式

新書上架~&#x1f447;全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目錄 一、直觀創建法&#xff1a;直接定義鍵值對 二、函數式創建法&#xff1a;使用內置函數dict…

CSRF 攻擊

概述 CSRF(Cross-site request forgery,跨站請求偽造)。 它是指攻擊者利用了用戶的身份信息&#xff0c;執行了用戶非本意的操作。 它首先引導用戶訪問一個危險網站&#xff0c;當用戶訪問網站后&#xff0c;網站會發送請求到被攻擊的站點&#xff0c;這次請求會攜帶用戶的c…

拼多多攜手中國農業大學,投建陜西佛坪山茱萸科技小院

5月16日下午&#xff0c;中國農業大學陜西佛坪山茱萸科技小院在佛坪縣銀廠溝村揭牌。佛坪縣素有“中國山茱萸之鄉”的美譽&#xff0c;是全國山茱萸三大基地之一&#xff0c;當地山茱萸是國家地理標志產品&#xff0c;山茱萸肉產量位居全國第二。 為充分發揮佛坪縣得天獨厚的山…

vscode快捷鍵mac快捷鍵

vscode快捷鍵 在 Visual Studio Code 中&#xff0c;可以使用「Ctrl D」快捷鍵來選中相同內容。還可以使用以下快捷鍵來操作&#xff1a; 向上/下選擇相同內容 Alt ↑/↓ 選擇所有相同內容 Ctrl Shift L mac中則是commandshiftL VSCode刪除整行快捷鍵 CtrlShiftK mac中則…

局部放電試驗變頻電源

局部放電試驗中的變頻電源設備 局部放電試驗變頻電源是一種專為電力設備的局部放電檢測設計的高性能電源系統。在電力設備的運行和維護過程中&#xff0c;局部放電測試用于探測潛在的絕緣缺陷&#xff0c;防止它們進一步惡化導致設備損壞。傳統的局部放電試驗通常使用交流電源&…

with關鍵字

在 Python 中&#xff0c;with 是一個關鍵字&#xff0c;用于引入一個上下文管理器&#xff08;context manager&#xff09;。上下文管理器是一種特殊的對象&#xff0c;它允許你以一種干凈、結構化的方式執行一組特定的操作&#xff0c;通常包括設置和清理資源。 with 語句通…

jmeter之測試計劃

一、測試計劃作用 測試計劃是jmeter的默認控件所有線程組都是測試計劃的下級控件測試計劃可以配置用戶自定義的變量測試計劃可以配置線程組的串行或并行 二、查看界面 名稱&#xff1a;可以修改自定義的名稱注釋&#xff1a;解釋測試計劃是用來做什么的用戶自定義的變量&…

Sentinel重要的前置知識

文章目錄 1、雪崩問題及解決方案1.1、雪崩問題1.2、超時處理1.3、倉壁模式1.4、斷路器1.5、限流1.6、總結 2、服務保護技術對比3、Sentinel介紹和安裝3.1、初識Sentinel3.2、安裝Sentinel 4、微服務整合Sentinel ?&#x1f343;作者介紹&#xff1a;雙非本科大三網絡工程專業在…

PX4使用yolo仿真環境搭建

文章目錄 前言一、修改機架sdf文件二、安裝yolo三、運行 前言 ubuntu20.04 PX4 1.13.3 已配置好PX4 ROS gazebo環境 一、修改機架sdf文件 將雙目相機加到仿真的iris機架上 修改下圖文件 添加如下&#xff1a; <include><uri>model://stereo_camera</uri>…

用nn.Sequential實現圖像的數據增強(augmentations)

代碼example: import torch import torch.nn as nn# 定義一些增強操作&#xff0c;例如隨機水平翻轉和歸一化 augmentations nn.Sequential(nn.RandomHorizontalFlip(),nn.Normalize(mean[0.5], std[0.5]) )# 創建一個示例 tensor candidate torch.randn(1, 3, 224, 224) #…

QWRT改AP模式 自動獲取IP

關閉&#xff08;禁用&#xff09;WAN 和 WAN6接口修改LAN接口 IP地址 改為上級路由的網段&#xff0c;如主路由器IP192.168.2.1&#xff0c;那么就設置為192.168.2.2&#xff08;不要沖突了&#xff09;IPv4 網關 改為上級路由的IP地址&#xff0c;如主路由器IP192.168.2.1&am…

使用 CapSolver API 服務解決 Arkose Labs FunCaptcha 驗證碼

使用 CapSolver API 服務解決 Arkose Labs FunCaptcha 驗證碼 FunCaptcha 以其復雜的圖像驗證而聞名&#xff0c;對自動化系統構成了巨大的挑戰。CapSolver 的 API 服務利用先進的 AI 技術輕松應對和解決 FunCaptcha 挑戰。本指南探討了 CapSolver 如何實現無縫自動化&#xff…

什么是html

HTML&#xff08;HyperText Markup Language&#xff0c;超文本標記語言&#xff09;是一種用于創建網頁的標準標記語言。它描述了一個網站的結構骨架&#xff0c;使得瀏覽器能夠展示具有特定格式的文本、鏈接、圖片和其他內容。HTML 文檔由一系列的元素構成&#xff0c;這些元…

STM32筆記-AD模數轉換

目錄 一、ADC介紹 二、ADC主要特征 三、ADC框圖 1. ???? 外部觸發轉換 ? 2. 轉換模式 3. 輸入通道 4. 邏輯框圖 四、校準 五、數據對齊 六、AD轉換步驟 七、AD_Init(單通道AD轉換)初始化函數配置 DMA: adc_dma_mode_enable(ADC0); 這段代碼是用來使能ADC的DMA&a…

ts 字符串不能做索引異常提示 type because expression of type ‘string‘

Element implicitly has an any type because expression of type string cant be used to index type 例子 let a{b:"1",c:"1" } var b"b"; let ca[b] let ca[b]就會爆這個錯誤&#xff0c;因為在編譯器看來b是一個未知的東西&#xff0c;它不…

什么是創造力?如何判斷自己的創造力?

創造力&#xff0c;主要表現為創新思想、發現和創造新事物的能力&#xff0c;是知識&#xff0c;智力和能力的綜合能力&#xff0c;尤其是在職業發展方面&#xff0c;創造力具有重要的意義&#xff0c;企業的核心競爭力就來源于創造力&#xff0c;這就需要具有創造力的員工來推…

ArduPilot開源飛控之MAVProxy深入研讀系列 - 1基本操作

ArduPilot開源飛控之MAVProxy深入研讀系列 - 1基本操作 1. 源由2. 基本操作2.1 二進制安裝2.2 源代碼安裝2.3 硬鏈接飛控2.4 軟連接飛控 3. 啟動參數3.1 輸入3.2 輸出3.3 日志3.4 交互3.5 其他 4. 參考資料 1. 源由 玩開源&#xff0c;就盡量不要用Windows/Android/iOS/MaxOS什…