C#基礎篇——反射

来源:https://www.cnblogs.com/i3yuan/archive/2020/03/15/12494501.html
-Advertisement-
Play Games

前言 在探究地球內部的結構中,如何做到在地球錶面不用深入地球內部就可以知道內部的構造呢?其實,向地球發射“地震波”。利用這種方式,可以判斷地球放回的情況,大體上,我們也可以斷定地球內部的構造了。 從這個例子中,通過一個對象的外部去瞭解對象內部的構造,都是利用了波的反射功能。而利用這種原理,在編程程式 ...


前言

  在探究地球內部的結構中,如何做到在地球錶面不用深入地球內部就可以知道內部的構造呢?其實,向地球發射“地震波”。利用這種方式,可以判斷地球放回的情況,大體上,我們也可以斷定地球內部的構造了。

  從這個例子中,通過一個對象的外部去瞭解對象內部的構造,都是利用了波的反射功能。而利用這種原理,在編程程式時,我們如何也可以實現從對象的外部來瞭解對象以及程式集內部的結構功能?在.NET中的反射,不僅可以實現外部對內部的瞭解,也同時可以動態創建出對象並執行其中的方法。

  反射是.NET中的重要機制,通過反射,可以在運行時獲得程式或程式集中每一個類型(包括類、結構、委托、介面和枚舉等)的成員和成員的信息。有了反射,即可對每一個類型瞭如指掌。另外我還可以直接創建對象,即使這個對象的類型在編譯時還不知道。 

開始

 一、使用的命名空間

    System.Reflection
    System.Type
    System.Reflection.Assembly

二、主要的類

    System.Type 類--通過這個類可以訪問任何給定數據類型的信息。
    System.Reflection.Assembly類--它可以用於訪問給定程式集的信息,或者把這個程式集載入到程式中。

說明

 一、System.Type類

 System.Type類對反射起著核心的作用。它是一個抽象的基類,Type有與每種數據類型對應的派生類,我們使用這個派生類的對象的方法、欄位、屬性來查找有關該類型的所有信息。

表示類型聲明:類類型、介面類型、數組類型、值類型、枚舉類型、類型參數、泛型類型定義,以及開放或封閉構造的泛型類型。

從Type中解析類型信息:

 A、判斷給定類型的引用的常用方式:

1.  使用C# typeof運算符

 Type t = typeof(string);

2. 使用對象GetType()方法

  string s = "i3yuan";
  Type t2 = s.GetType();

3.調用靜態Type類的靜態方法GetType()

  Type t3 = Type.GetType("System.String");

以上三種方式獲取類型Type後,可以應用t來探測string裡面的結構

  foreach (MemberInfo mi in t.GetMembers())
  {
       Console.WriteLine("{0}/t{1}", mi.MemberType, mi.Name);
  }

B、Type類屬性:

  1.命名空間和類型名

        Name 數據類型名
        FullName 數據類型的完全限定名(包括命名空間名)
        Namespace 定義數據類型的命名空間名

  2. 類和委托

        Type.IsClass   判斷一個類型是否為類或者委托。符合條件的會有普通的類(包括泛型)、抽象類(abstract class)、委托(delegate)

  3. 是否泛型  

        Type.IsGenericType 屬性可以判斷類或委托是否為泛型類型。

        Type.IsGenericTypeDefinition 屬性可以判斷Type是否是未綁定參數類型的泛型類型。

        Type.IsConstructedGenericType 屬性判斷是否可以此Type創建泛型實例。

  4.訪問修飾符

        Type.IsPublic 判斷該類型是否是公有的

        Type.IsNotPublic

  5.密封類、靜態類型、抽象類

        Type.IsSealed 判斷該類型是否是密封類,密封類不能被繼承

        IsAbstract 指示該類型是否是抽象類型

  6. 值類型

        Type.IsValueType 判斷一個 Type 是否為值類型,簡單值類型、結構體、枚舉,都符合要求。

        Type.IsEnum   判斷該類型是否是枚舉

        Type.IsPrimitive  判斷Type是否為基礎類型

  7.介面

        Type.IsInterface    判斷該類型是否是介面

  8.數組

        IsArray   判斷該類型是否是數組,GetArrayRank() 獲取數組的維數。

從Type類解析類型成員結構

一個類由以下一個或多個成員組成:

成員類型說明
PropertyInfo 類型的屬性信息
FieldInfo 類型的欄位信息
ConstructorInfo 類型的構造函數信息
MethodInfo 類型的方法
ParameterInfo 構造函數或方法的參數
EventInfo 類型的事件

C、Type類的方法

    public class MySqlHelper
    {
        public MySqlHelper()
        {
            Console.WriteLine("{0}被構造", this.GetType().Name);
        }


        public void Query()
        {
            Console.WriteLine("{0}.Query", this.GetType().Name);
        }
    }

        GetConstructor(), GetConstructors():返回ConstructorInfo類型,用於取得該類的構造函數的信息

                    MySqlHelper dBHelper = new MySqlHelper();
                    Type type = dBHelper.GetType();
                    ConstructorInfo[] constructorInfos= type.GetConstructors();
                    foreach (var item in constructorInfos)
                    {
                        ParameterInfo[] parameterInfos = item.GetParameters();
                        foreach (var info in parameterInfos)
                        {
                            Console.WriteLine("查看:" + info.ParameterType.ToString() + "  " + info.Name);
                        }

                    }

        GetEvent(), GetEvents():返回EventInfo類型,用於取得該類的事件的信息

        GetField(), GetFields():返回FieldInfo類型,用於取得該類的欄位(成員變數)的信息

        MySqlHelper nc = new MySqlHelper();
        Type t = nc.GetType();
        FieldInfo[] fis = t.GetFields();
        foreach (FieldInfo fi in fis)
        {
            Console.WriteLine(fi.Name);
        } 

        GetInterface(), GetInterfaces():返回InterfaceInfo類型,用於取得該類實現的介面的信息

        GetMember(), GetMembers():返回MemberInfo類型,用於取得該類的所有成員的信息

            string n = "i3yuan";
            Type t = n.GetType();
            foreach (MemberInfo mi in t.GetMembers())
            {
                Console.WriteLine("{0}/t{1}",mi.MemberType,mi.Name);
            }

        GetMethod(), GetMethods():返回MethodInfo類型,用於取得該類的方法的信息

        MySqlHelper dBHelper= new MySqlHelper();
        Type t = dBHelper.GetType();
        MethodInfo[] mis = t.GetMethods();
        foreach (MethodInfo mi in mis)
        {
            Console.WriteLine(mi.ReturnType+" "+mi.Name);
        }

        GetProperty(), GetProperties():返回PropertyInfo類型,用於取得該類的屬性的信息

        MySqlHelper dBHelper= new MySqlHelper();
        Type t = dBHelper.GetType();
        PropertyInfo[] pis = t.GetProperties();
        foreach(PropertyInfo pi in pis)
        {
            Console.WriteLine(pi.Name);
        }

  可以調用這些成員,其方式是調用Type的InvokeMember()方法,或者調用MethodInfo, PropertyInfo和其他類的Invoke()方法。 

  用反射生成對象,並調用屬性、方法和欄位進行操作 

        //獲取類型信息
        MySqlHelper dbHelper=new MySqlHelper();
        Type type=dbHelper.GetType
        //創建對象實例化
        object DbHelper = Activator.CreateInstance(type);
        //類型轉換
        IDBHelper iDBHelper = (IDBHelper)DbHelper;
        //方法調用
        iDBHelper.Query();    

 

二、System.Reflection.Assembly類

   Assembly類可以獲得程式集的信息,也可以動態的載入程式集,以及在程式集中查找類型信息,並創建該類型的實例。使用Assembly類可以降低程式集之間的耦合,有利於軟體結構的合理化

 1. System.Reflection 

用於訪問給定程式集的信息,或者把這個程式集載入到程式中。可以讀取並使用metadata

方法調用過程:

1.載入DLL  ; 2. 獲取類型信息 ;3. 創建對象類型  4. 類型轉換  5. 方法調用

                    Assembly assembly = Assembly.Load("Yuan.DB.MySql");//dll名稱無尾碼  從當前目錄載入  1 載入dll
                    //完整路徑的載入  可以是別的目錄   載入不會錯,但是如果沒有依賴項,使用的時候會錯
                    Type type = assembly.GetType("Yuan.DB.MySql.MySqlHelper");//2 獲取類型信息
                    object oDBHelper = Activator.CreateInstance(type);//3 創建對象
                    //oDBHelper.Query();//oDBHelper是objec不能調用,但實際上方法是有的   編譯器不認可  
                    IDBHelper iDBHelper = (IDBHelper)oDBHelper;//4 類型轉換
                    iDBHelper.Query();//5 方法調用

方法二:通過程式集的名稱反射

                    Assembly assembly = Assembly.Load("Yuan.DB.MySql");//dll名稱無尾碼  從當前目錄載入  1 載入dll
               
                    Type type = assembly.GetType("Yuan.DB.MySql.MySqlHelper");//2 獲取類型信息

                    object oDBHelper = Activator.CreateInstance(type);//3 創建對象
                   MethodInfo mi=oDBHelper.GetMethod("Query"); //獲取方法
                    mi.Invoke(oDBHelper,null);//5 調用

總結

  1. 作為一個開發人員,在每天都會應用到反射,使用的時候,會反射當前程式的元數據,將所有的方法,類等信息都全部顯示出來,以便開發人員使用,大大的提高了效率

  2. 同時反射提高了程式的靈活性和拓展性,降低耦合,動態載入,允許控制和實現任何類的對象。

  3. 當然了,也存在弊端,寫起來複雜,也存在性能問題,用於欄位和方法接入時要遠慢於直接代碼。

  參考 文檔 和 《C#圖解教程》

  註:搜索關註公眾號【雜學谷】--回覆【C#圖解】,可獲取 C#圖解教程文件


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

-Advertisement-
Play Games
更多相關文章
  • 安裝:pip install BeautifulSoup4 下表列出了主要的解析器,以及它們的優缺點:看個人習慣選取自己喜歡的解析方式 1 # 獲取html代碼 2 import requests 3 r = requests.get('http://www.python123.io/ws/demo ...
  • 通過一個例子說明瞭C++中自定義結構體或類作為關聯容器的鍵時的問題:需要定義排序規則。 ...
  • 1、逢7跳過小游戲:從1-100之間,遇到帶7的數字或者7的倍數跳過。 1 for i in range(1,101): 2 if i == 7 or i % 10 == 7 or i // 10 == 7: 3 continue 4 else: 5 print(i,end = ",") 2、七段數 ...
  • In [1]: import os import matplotlib.image as mpimg from PIL import Image import matplotlib.pyplot as plt import numpy as np import matplotlib as mpl m ...
  • Redis 在當前的技術社區里是非常熱門的。從來自 Antirez 一個小小的個人項目到成為記憶體數據存儲行業的標準,Redis已經走過了很長的一段路。 隨之而來的一系列最佳實踐,使得大多數人可以正確地使用 Redis。 下麵我們將探索正確使用 Redis 的10個技巧。 1、停止使用 KEYS Ok ...
  • 最近在使用ASP.NET Core的時候出現了一個奇怪的問題。在一個Controller上使用了一個ActionFilter之後經常出現EF報錯。 這個異常說Context在完成前一個操作的時候第二個操作依據開始。這個錯誤還不是每次都會出現,只有在併發強的時候出現,基本可以判斷跟多線程有關係。看一下 ...
  • 如何自行實現一個多租戶系統 註意:前情概要描述的文字比較多,說的是我的思考過程,不感興趣的可以直接到跳到 “解析租戶信息” 一節。 現如今框架滿天飛的環境下,好像很少機會需要自己來實現一個模塊。畢竟這樣能節省很多的開發時間,提高效率。 這就是框架的好處,也是我們使用框架的直接原因。 情況總有例外,假 ...
  • 前言 我們一般可以在Linux伺服器上執行 命令來運行我們的.net Core WebApi應用。但是這樣運行起來的應用很不穩定,關閉終端視窗之後,應用也會停止運行。為了讓其可以穩定運行,我們需要讓它變成系統的守護進程,成為一種服務一直在系統中運行,出現異常時也能重新啟動。 Linux系統有自己的守 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...