當前位置: 妍妍網 > 碼農

反射的底層實作原理及C#範例

2024-06-18碼農

反射(Reflection)是.NET框架提供的一種機制,它允許程式在執行時獲取型別的詳細資訊,並且能夠動態地建立和呼叫型別的方法、內容等。反射是.NET框架中非常強大的功能,但同時也是一個相對重量級的操作,因為它涉及到後設資料的載入和解析。

反射的底層實作原理

在.NET中,每個型別(包括類、結構、列舉等)在編譯時都會被編譯成後設資料(Metadata)和IL程式碼(中間語言程式碼)。後設資料描述了型別的名稱、基礎類別、實作的介面、擁有的方法和內容等資訊,而IL程式碼則是型別的實際執行邏輯。

當.NET程式執行時,CLR(公共語言執行時)會載入程式集(Assembly),並解析其中的後設資料和IL程式碼。反射就是透過CLR提供的API來存取和操作這些後設資料的過程。

具體來說,反射的實作原理可以分為以下幾個步驟:

  1. 載入程式集 :首先,需要載入包含目標型別的程式集。這可以透過 Assembly.Load Assembly.LoadFrom 等方法實作。

  2. 獲取型別資訊 :一旦程式集被載入,就可以透過 Assembly.GetType Type.GetType 等方法獲取到程式集中的型別資訊。這些資訊以 Type 物件的形式表示。

  3. 反射操作 :有了 Type 物件後,就可以透過它來獲取型別的成員資訊(如方法、內容、欄位等),或者建立型別的例項,甚至動態呼叫型別的方法。

C#反射範例

下面是一個簡單的C#範例,演示了如何使用反射來獲取一個類的資訊,並動態呼叫其方法:

using System;
using System.Reflection;
namespaceReflectionExample
{
classProgram
{
staticvoidMain(string[] args)
{
// 載入程式集並獲取型別資訊
Assembly assembly = Assembly.GetExecutingAssembly(); // 獲取當前執行的程式集
Type type = assembly.GetType("ReflectionExample.My class"); // 獲取My class的型別資訊
// 建立型別的例項
object obj = Activator.CreateInstance(type); // 建立My class的例項
// 獲取並呼叫方法
MethodInfo methodInfo = type.GetMethod("SayHello"); // 獲取SayHello方法的資訊
methodInfo.Invoke(obj, null); // 動態呼叫SayHello方法,註意這裏傳遞了null因為該方法沒有參數
// 獲取並設定內容
PropertyInfo propertyInfo = type.GetProperty("Name"); // 獲取Name內容的資訊
propertyInfo.SetValue(obj, "Alice"); // 設定Name內容的值為"Alice"
Console.WriteLine($"Name property set to: {propertyInfo.GetValue(obj)}"); // 獲取並打印Name內容的值
}
}
classMy class
{
publicstring Name { getset; } = "Unknown";
publicvoidSayHello()
{
Console.WriteLine($"Hello, my name is {Name}!");
}
}
}




在這個範例中,我們首先載入了當前執行的程式集,並從中獲取了 My class 的型別資訊。然後,我們使用 Activator.CreateInstance 方法動態建立了 My class 的一個例項。接著,我們透過反射獲取了 SayHello 方法的資訊,並使用 MethodInfo.Invoke 方法動態呼叫了這個方法。最後,我們還透過反射獲取並設定了 My class Name 內容。

總結

反射是.NET框架中一項強大的技術,它允許開發者在執行時動態地獲取和操作型別的後設資料。透過反射,我們可以實作很多高級功能,比如外掛程式系統、序列化/反序列化、ORM對映等。然而,需要註意的是,反射操作相對較重,會消耗更多的資源,因此在效能敏感的場景中需要謹慎使用。