詳解C#特性和反射(二)

来源:https://www.cnblogs.com/minotauros/archive/2018/09/26/9709491.html
-Advertisement-
Play Games

使用反射(Reflection)使得程式在運行過程中可以動態的獲取對象或類型的類型信息,然後調用該類型的方法和構造函數,或訪問和修改該類型的欄位和屬性;可以通過晚期綁定技術動態的創建類型的實例;可以獲取程式集中的所有類型信息;可以在動態構建新類型;還可以檢索元素所添加的特性; ※反射相關的類基本都位 ...


  使用反射(Reflection)使得程式在運行過程中可以動態的獲取對象或類型的類型信息,然後調用該類型的方法和構造函數,或訪問和修改該類型的欄位和屬性;可以通過晚期綁定技術動態的創建類型的實例;可以獲取程式集中的所有類型信息;可以在動態構建新類型;還可以檢索元素所添加的特性;
  ※反射相關的類基本都位於命名空間System.Reflection中;
  ※動態構建新類型的類位於命名空間System.Reflection.Emit中;


  一、訪問或修改類型的實例、靜態欄位:

public class MyClass
{
    public int myField;
    public static int myStaticField;
}

//使用方式:
//訪問或修改類型的實例欄位myField
MyClass myObj = new MyClass() { myField = 1 }; //創建實例
Type myType = typeof(MyClass); //獲取類型,或myObj.GetType()
FieldInfo fieldInfo = myType.GetField("myField"); //獲取類型中指定的欄位信息
Console.WriteLine((int)fieldInfo.GetValue(myObj)); //1,獲取實例欄位的值
fieldInfo.SetValue(myObj, 2); //給實例欄位賦值
//訪問或修改類型的靜態欄位myStaticField
FieldInfo staticFieldInfo = myType.GetField("myStaticField"); //獲取類型中指定的欄位信息
Console.WriteLine(staticFieldInfo.GetValue(null)); //0,獲取靜態欄位的值
staticFieldInfo.SetValue(null, 2); //給靜態欄位賦值

  ※與直接賦值相比,使用反射賦值用時約長75倍,使用以下代碼多次測試:

public class MyClass
{
    public int myField;
}

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        MyClass myObj = new MyClass() { myField = 1 };
        Type myType = typeof(MyClass);
        FieldInfo fieldInfo = myType.GetField("myField");

        stopwatch.Start();
        for (int i = 0; i < 10_000_000; i++)
        {
            fieldInfo.SetValue(myObj, 2);
        }
        stopwatch.Stop();
        Console.WriteLine($"使用反射賦值1千萬次耗時:{stopwatch.ElapsedMilliseconds}");

        stopwatch.Reset();
        stopwatch.Start();
        for (int i = 0; i < 10_000_000; i++)
        {
            myObj.myField = 2;
        }
        stopwatch.Stop();
        Console.WriteLine($"直接賦值1千萬次耗時:{stopwatch.ElapsedMilliseconds}");
        Console.Read();
    }
}

  二、訪問或修改類型的實例、靜態屬性:

public class MyClass
{
    public int MyProperty { get; set; }
    public static int MyStaticProperty { get; set; }
}
//使用方式:
//訪問或修改類型的實例屬性MyProperty MyClass myObj = new MyClass() { MyProperty = 1 }; //創建實例 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() PropertyInfo propertyInfo = myType.GetProperty("MyProperty"); //獲取類型中指定的屬性信息 Console.WriteLine((int)propertyInfo.GetValue(myObj, null)); //1,獲取實例屬性的值 propertyInfo.SetValue(myObj, 2, null); //給實例屬性賦值 //訪問或修改類型的靜態屬性MyStaticProperty PropertyInfo staticPropertyInfo = myType.GetProperty("MyStaticProperty"); //獲取類型中指定的屬性信息 Console.WriteLine(staticPropertyInfo.GetValue(null, null)); //0,獲取靜態屬性的值 staticPropertyInfo.SetValue(null, 2); //給靜態屬性賦值

  ※在使用反射給屬性賦值時,如果該屬性不具有set訪問器,則會拋出異常ArgumentException;

  三、調用類型的方法:

public class MyClass
{
  public void MyFunc(int num)
  {
    Console.WriteLine("MyFunc(int num) execute, the parameter is: " + num);
  }
  public static void MyStaticFunc(int num)
  {
      Console.WriteLine("MyStaticFunc(int num) execute, the parameter is: " + num);
  }
}
//使用方式:
//調用類型的實例方法MyFunc MyClass myObj = new MyClass(); //創建實例 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() MethodInfo methodInfo = myType.GetMethod("MyFunc"); //獲取類型中指定的方法信息 methodInfo.Invoke(myObj, new object[] { 10 }); //調用實例方法,並傳入參數,無參傳null //MyFunc(int num) execute, the parameter is: 10 //調用類型的實例方法MyStaticFunc MethodInfo staticMethodInfo = myType.GetMethod("MyStaticFunc"); //獲取類型中指定的方法信息 staticMethodInfo.Invoke(null, new object[] { 20 }); //調用靜態方法,並傳入參數,無參傳null //MyStaticFunc(int num) execute, the parameter is: 20

  四、調用類型的構造函數同時創建實例:

public class MyClass
{
    public MyClass()
    {
        Console.WriteLine("MyClass() execute.");
    }
    public MyClass(int num)
    {
        Console.WriteLine("MyClass(int num) execute, the parameter is: " + num);
    }
}
//使用方式:
//調用無參的構造函數 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() ConstructorInfo constructorInfo = myType.GetConstructor(new Type[] { }); //獲取類型中指定的構造函數信息,傳入該構造函數的參數列表的類型數組,無參傳空數組 MyClass myObj = constructorInfo.Invoke(null) as MyClass; //通過調用構造函數創建實例,無參傳null //MyClass() execute. //調用帶參數的構造函數 constructorInfo = myType.GetConstructor(new Type[] { typeof(int) }); //獲取類型中指定的構造函數信息,傳入該構造函數的參數列表的類型數組 myObj = constructorInfo.Invoke(new object[] { 20 }) as MyClass; //通過調用構造函數創建實例,並傳入參數 //MyClass(int num) execute, the parameter is: 20

  ※也可以使用Type類中的實例方法InvokeMember()來調用指定成員;

  五、使用反射查找特性:

  1.如果元素使用了特性,在沒有檢索並對其進行操作前該特性沒有任何價值,可以使用反射在程式運行過程中獲取元素添加的特性然後對其進行操作,使用特性基類Attribute中的靜態方法GetCustomAttributes(MemberInfo element)或命名空間System.Reflection中的擴展方法GetCustomAttributes(this MemberInfo element)來獲取類型或成員的所有特性信息:

Attribute[] attributes = Attribute.GetCustomAttributes(typeof(MyClass));
//IEnumerable<Attribute> attributes = typeof(MyClass).GetCustomAttributes();
foreach (var item in attributes)
{
  if (item is MyselfAttribute)
  {
    MyselfAttribute attribute = item as MyselfAttribute;
    Console.WriteLine(attribute .ClassName + " " + attribute .Author); //MyClass Me
  }
}

  2.這兩個方法都有對應的重載方法,可以傳入要檢索的指定特性的類型,這樣即可得到元素中所有指定類型的特性信息:

Attribute[] attributes = Attribute.GetCustomAttributes(typeof(MyClass), typeof(MyselfAttribute));
//IEnumerable<Attribute> attributes = typeof(MyClass).GetCustomAttributes(typeof(MyselfAttribute));
foreach (var item in attributes)
{
  MyselfAttribute attribute = item as MyselfAttribute;
  Console.WriteLine(attribute.ClassName + " " + attribute.Author); //MyClass Me
}

  ※如果未找到任何特性或指定類型的特性,這些方法會返回一個空數組;

  3.也可以使用基類Attribute中的靜態方法GetCustomAttribute(MemberInfo element, Type attributeType)或命名空間System.Reflection中的擴展方法GetCustomAttribute(this MemberInfo element, Type attributeType)來獲取類型或成員的指定特性信息;
  ※如果未找到指定類型的特性,會返回null;
  ※在檢索的元素中存在多個相同的指定類型的特性時,會拋出異常Reflection.AmbiguousMatchException;

 

  類型信息、晚期綁定、動態創建類型等會在下一篇中介紹。

 


 

如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的認可是我寫作的最大動力!

作者:Minotauros
出處:https://www.cnblogs.com/minotauros/

本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重覆的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。 1.前序遍歷是中,左,右;中序遍歷是左,中,右 2.前序遍歷的... ...
  • 讀書筆記 kancy ...
  • 為了用事實說明挖掘機技術到底哪家強,PAT 組織了一場挖掘機技能大賽。現請你根據比賽結果統計出技術最強的那個學校。 輸入格式: 輸入在第 1 行給出不超過 1 的正整數 N,即參賽人數。隨後 N 行,每行給出一位參賽者的信息和成績,包括其所代表的學校的編號(從 1 開始連續編號)、及其比賽成績(百分 ...
  • 為什麼選擇 Java 想必有很多初學者會像我一樣,不知選擇什麼語言入門。在嘗試了 C、C++、C 、Python、PHP 後,我決定把 Java作 為第一門深入學習的編程語言。這個路著實有點長...... 不過放心,你可以大膽地選擇 Java。如果說 C++ 是編程界的曹操,那 Java 就是司馬懿 ...
  • 說明:小數點“.”後面的“*”表示輸出位數,具體的數據來自參數表。 printf格式字元串中,與寬度控制和精度控制有關的常量都可以換成變數,方法就是使用一個“*”代替那個常量,然後在後面提供變數給“*”。 同樣,小數點“.”前面也可以添加“*”,也要用戶輸入一個位寬值來代替,表示輸出的字元所占位寬。 ...
  • YouPBX YouPBX 是一個強大 FreeSwift (電話軟交換系統) 的管理GUI系統,基於Django開發,功能全面,體驗友好,可以基於此項目做一個完善的IPPBX系統、呼叫中心應用等 項目地址 https://github.com/JoneXiong/YouPBX 使用 ...
  • 調用加密 解密看效果 ...
  • 概念 異常處理是指程式在運行過程中,發生錯誤會導致程式退出,這種錯誤,就叫做異常 但並不是所有的錯誤都是異常 而處理這種錯誤,稱為異常處理 異常處理實際是不斷去發掘異常、修改異常,使程式更穩定 異常處理主要表現在四個方面: 程式開發前:儘可能的想到會發生的錯誤,標註怎麼處理應對 程式開發中:儘量暴露 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...