首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 反射機制深度解析:動態載入、實例化與方法呼叫完整實戰

     編輯:關於C語言

什麼是反射?

反射(Reflection)讓程式在執行時期檢查、操作組件、模組、類型、成員(欄位、屬性、方法、事件)的中繼資料,並支援動態建立實例、呼叫方法、存取屬性。核心命名空間:System.Reflection。

核心類別速查

類別用途
Assembly載入組件、列舉型別、取得資源
Type型別中繼資料核心,取得建構函式、方法、屬性、欄位
MethodInfo方法資訊,Invoke(obj, params) 動態呼叫
ConstructorInfo建構函式資訊,Invoke(params) 動態實例化
PropertyInfo / FieldInfo屬性/欄位資訊,GetValue/SetValue 存取
EventInfo事件資訊,動態加入/移除處理器

完整實戰範例:跨組件動態實例化與方法呼叫

類別庫專案

// Example25Lib.dll
namespace Example25Lib {
    public class Class1 {
        private string _name;
        private int _age;
        public Class1(string name, int age) { _name = name; _age = age; }
        public void ChangeName(string newName) => _name = newName;
        public void ChangeAge(int newAge) => _age = newAge;
        public override string ToString() => $"Name: {_name}, Age: {_age}";
    }
}

主程式:反射載入、建構、呼叫

using System;
using System.Reflection;

namespace Example25 {
    class Program {
        static void Main() {
            // 1. 載入組件(絕對路徑)
            string dllPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Example25Lib.dll");
            Assembly asm = Assembly.LoadFile(dllPath);

            // 2. 列舉所有公開類型
            foreach (Type type in asm.GetTypes()) {
                Console.WriteLine($"發現類型: {type.FullName}");

                // 3. 取得所有公開建構函式
                foreach (ConstructorInfo ctor in type.GetConstructors()) {
                    // 4. 準備建構函式參數
                    ParameterInfo[] ctorParams = ctor.GetParameters();
                    object[] args = new object[ctorParams.Length];
                    for (int i = 0; i < ctorParams.Length; i++) {
                        Type pt = ctorParams[i].ParameterType;
                        if (pt == typeof(string)) args[i] = "Clark";
                        else if (pt == typeof(int)) args[i] = 0;
                        else args[i] = Activator.CreateInstance(pt); // 嘗試預設建構
                    }

                    // 5. 動態實例化
                    object instance = ctor.Invoke(args);
                    Console.WriteLine($"實例化: {instance}");

                    // 6. 取得所有公開方法並呼叫
                    foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) {
                        ParameterInfo[] mParams = method.GetParameters();
                        object[] mArgs = new object[mParams.Length];
                        for (int i = 0; i < mParams.Length; i++) {
                            Type pt = mParams[i].ParameterType;
                            if (pt == typeof(string)) mArgs[i] = "Clark Zheng";
                            else if (pt == typeof(int)) mArgs[i] = 27;
                            else mArgs[i] = Activator.CreateInstance(pt);
                        }
                        method.Invoke(instance, mArgs);
                    }

                    // 7. 再次輸出驗證狀態變更
                    Console.WriteLine($"呼叫後: {instance}");
                }
            }
            Console.ReadLine();
        }
    }
}

執行結果

發現類型: Example25Lib.Class1
實例化: Name: Clark, Age: 0
呼叫後: Name: Clark Zheng, Age: 27

反射常見應用場景

  1. 外掛/擴充架構:掃描目錄載入實作特定介面的組件
  2. 序列化/反序列化:JSON.NET、XmlSerializer 內部大量使用反射
  3. ORM 映射:Entity Framework、Dapper 透過反射映射資料庫欄位
  4. 依賴注入容器:Autofac、Unity 掃描建構函式自動解析依賴
  5. 單元測試框架:NUnit/xUnit 發現 [Test] 屬性標記的方法
  6. 動態代理/AOP:Castle DynamicProxy 攔截方法呼叫

效能與安全性考量

  • 效能開銷:反射比直接呼叫慢 10-100 倍;熱路徑請緩存 MethodInfo/PropertyInfo、使用 Delegate.CreateDelegate 或 Expression Tree 編譯委託。
  • 安全性:ReflectionPermission 控管私有成員存取;沙箱環境可能受限。
  • 修剪相容:.NET Native / AOT 編譯會移除未靜態引用的型別/成員,需加 [DynamicDependency] 或保留屬性。

進階技巧:建立強型別委託提升效能

// 假設已取得 MethodInfo method
var func = (Func)Delegate.CreateDelegate(
    typeof(Func), null, method);
// 後續呼叫 func(instance, 42) 速度接近直接呼叫
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved