C# 映射( Reflection )

Reflection 之封面圖

在開發程式的過程中,常常會想要更加靈活的寫法,而這時映射(Reflection)可以大力的幫助到你, Reflection 允許我們的程式在執行時再去檢查和操作型別資訊,這對於如果你想要建立動態、可擴展的程式來說非常方便。接下來,我將介紹一些Reflection的基本用法並包含程式碼Code,以便幫助你更好的掌握這項技術。

第一步,我們需要引入Reflection所需的命名空間:

using System;

using System.Reflection;

接下來,建立一個MyClass

class MyClass
{
  public int MyProperty { get; set; }
  public void MyMethod()
  {
    // 輸出一段簡單的文字
   Console.WriteLine("Hello, World!");
  }
}

 

internal class Program
{
  static void Main(string[] args)
  {
   // 獲取類別型別資訊
   Type type = typeof(MyClass);
   Console.WriteLine("Class Name: " + type.Name);
   // 列出所有屬性
   foreach (var property in type.GetProperties())
   {
    Console.WriteLine("Property: " + property.Name);
   }
   // 列出所有方法
   foreach (var method in type.GetMethods())
   {
    Console.WriteLine("Method: " + method.Name);
   }
   // 暫停
   Console.ReadLine();
  }
}

執行結果如下:

Reflection 之說明圖

動態建立類型並叫用其方法

假設我們想要創建一個 MyClass 的實體,但不直接使用 new 關鍵字。可以使用 Activator.CreateInstance 方法:

Type type = typeof(MyClass);

// 動態建立 MyClass 的實體

object instance = Activator.CreateInstance(type);

 

// 使用 GetMethod 獲取名為 MyMethod 的方法

MethodInfo methodInfo = type.GetMethod(“MyMethod”);

// 使用 Invoke 方法來呼叫 MyMethod

methodInfo.Invoke(instance, null);

 

執行結果如下:

Reflection 之說明圖

在這段程式碼中,我們動態建立了 MyClass 的一個實體,並使用Reflection 呼叫了 MyMethod 方法。值得注意的是,如果MyClass擁有建構式,在Activator.CreateInstance時會一併呼叫其建構式。

 

修改屬性

Reflection也可以用來修改物件的屬性:

PropertyInfo propertyInfo = type.GetProperty(“MyProperty”);

propertyInfo.SetValue(instance, 42);

 

int propertyValue = (int)propertyInfo.GetValue(instance);

Console.WriteLine(“Property Value: “ + propertyValue);

 

執行結果如下:

透過這種方式,我們可以在不直接引用類別的情況下操作其屬性,這在動態程式設計時常常使用到。

 

呼叫私有成員

有些情況下,我們可能會需要呼叫私有類別的成員。雖然並不常這樣使用但 Reflection其實能做到這一點:

class MyClass
{
  //私有方法
  private void PrivateMethod()
  {
   Console.WriteLine("我是一個私有的方法。");
  }
}

 

// BindingFlags.NonPublic 表示搜尋私有(private)的成員

// BindingFlags.Instance 表示搜尋實例成員(非靜態成員)

MethodInfo privateMethod = type.GetMethod(“PrivateMethod”, BindingFlags.NonPublic | BindingFlags.Instance);

privateMethod.Invoke(instance, null);

 

執行結果如下:

通過 BindingFlags,我們可以去指定私有方法。但必須特別注意,請減少使用這種做法,因為這麼做可能違反了物件導向程式設計的封裝原則,且也可能違背了當初程式開發人員所設計的邏輯。

 

使用時的注意事項

雖然Reflection很方便,但在使用時也要注意以下幾點:

  • 性能:Reflection可能會比直接呼叫來的慢,在一些需要頻繁使用的情境下,還是要考慮Reflection的必要性。
  • 安全性:通過Reflection訪問私有的屬性、方法可能會導致問題。
  • 可維護性:當過度使用Reflection時,有可能導致程式變得難以理解和維護。
  • 躲避編譯器檢查:在平時直接呼叫方法如果有錯,在編譯時就可以發現錯誤,但使用Reflection時,往往需要你在執行當下才可以發現錯誤。

結論

Reflection是 C# 提供的非常有用的工具,能夠使我們靈活的去撰寫程式碼,Reflection的各種動態地呼叫方法、建立物件等操作讓初次接觸的我完全沉迷於其中,但在使用時真的不得不謹慎,由於繞過了編譯時的型別檢查和安全檢查,除了確保程式的效能和安全性,還得考慮程式的可讀性與可維護性。希望這篇文章有幫助到你,謝謝

 

參考資料:

https://learn.microsoft.com/zh-tw/dotnet/csharp/advanced-topics/reflection-and-attributes/

Comments

No comments yet. Why don’t you start the discussion?

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料