解釋 .NET 框架中的反射是如何工作的


一個 C# 程式編譯成一個 DLL 程式集,其中包含已編譯的 C# 程式碼以及執行時的元資料和其他資源。C# 提供了一個反射 API,允許我們在執行時檢查元資料和已編譯的程式碼。

使用反射,可以:

  • 訪問程式集元資料以獲取程式集內所有型別的資訊

  • 獲取型別及其成員(方法、屬性等)的列表

  • 在執行時動態呼叫型別成員。

  • 僅提供型別名稱即可例項化物件

  • 構建程式集

在傳統的程式中,當您將原始碼編譯成機器碼時,編譯器會刪除有關程式碼的所有元資料。但是,由於 C# 是一種在公共語言執行時 (CLR) 中執行的託管語言,因此編譯器會保留有關程式碼的大部分資訊。反射允許我們檢查程式集中的元資料。

System.Reflection 名稱空間包含反射所需的所有類和其他型別。您還可以透過 System.Reflection.Emit 名稱空間中的型別建立新的元資料併發出中間語言 (IL) 中的可執行程式碼。

System.Type 使您可以訪問型別的元資料。此物件還包含用於列舉型別例項成員的方法,您可以呼叫這些方法。

using System;
using System.Text;
using System.Reflection;

var sb = new StringBuilder();

// Type at runtime
Type t1 = sb.GetType();
Console.WriteLine(t1.FullName); // System.Text.StringBuilder

// Type at compile-time
Type t2 = typeof (StringBuilder);
Console.WriteLine(t2.FullName); // System.Text.StringBuilder

還可以根據對程式集的引用按名稱獲取型別。以下示例使用當前程式集並獲取在 Models 名稱空間中定義的 Person 類的型別。

Type personType = Assembly.GetExecutingAssembly().GetType("CSharp.Models.Person");
Console.WriteLine(personType.FullName); // CSharp.Models.Person

Type 類有一些有用的屬性,您可以使用這些屬性訪問型別的名稱、程式集、可見性、基型別等。

using System;
using System.Text;
using System.Reflection;
var sb = new StringBuilder();
// Type at runtime
Type t1 = sb.GetType();
// What's the type's name?
Console.WriteLine(t1.FullName); // System.Text.StringBuilder
// What's the type's base type?
Console.WriteLine(t1.BaseType); // System.Object
// Which assembly is the type defined in?
Console.WriteLine(t1.Assembly); // System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
// Is the type public?
Console.WriteLine(t1.IsPublic); // True

除了這些屬性之外,還有 GetProperties()、GetMethods() 和 GetFields() 等方法可以訪問型別的成員。重要的是獲取對型別 Type 物件的引用。有兩種方法可以實現此目的:

object.GetType()

所有型別都包含此函式。它在執行時返回型別

typeof(class)

此表示式在編譯時獲取型別。它在編譯時繫結到特定的 Type 例項,並且直接將型別作為引數。

System.Reflection 名稱空間中的類以及 System.Type 名稱空間中定義的類允許您獲取有關程式集及其內部型別(例如類、介面和值型別)的資訊。

更新於: 2021年5月19日

310 次瀏覽

啟動您的 職業生涯

透過完成課程獲得認證

開始學習
廣告