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

C# 反射實戰:動態加載程序集、屬性讀寫、方法調用、DataTable 轉實體

     編輯:關於C#

反射核心場景

反射讓代碼在運行時檢查、操作類型。典型應用:插件系統、ORM 映射、配置驅動、序列化框架。

核心封裝類:ObjectLoader

public class ObjectLoader
{
    private readonly Assembly _assembly;

    public ObjectLoader(string assemblyName) 
        => _assembly = Assembly.Load(assemblyName);

    // 1. 創建實例 (需含命名空間)
    public object CreateInstance(string typeName)
        => _assembly.CreateInstance($"{_assembly.GetName().Name}.{typeName}");

    // 2. 獲取所有公共屬性
    public PropertyInfo[] GetProperties(object obj)
        => obj.GetType().GetProperties();

    // 3. 設置屬性值
    public void SetProperty(object obj, string propName, object value)
    {
        var prop = obj.GetType().GetProperty(propName);
        prop?.SetValue(obj, value, null);
    }

    // 4. 讀取屬性值
    public object GetProperty(object obj, string propName)
    {
        var prop = obj.GetType().GetProperty(propName);
        return prop?.GetValue(obj, null);
    }

    // 5. 執行無參方法
    public void InvokeMethod(object obj, string methodName)
    {
        var method = obj.GetType().GetMethod(methodName);
        method?.Invoke(obj, null);
    }
}

測試用實體 (Model.dll)

namespace Model
{
    public class UserInfo
    {
        public int UserId { get; set; }
        public string UserName { get; set; }
        public void Show() => Console.WriteLine($"UserId:{UserId}, UserName:{UserName}");
    }
}

控制台測試

var loader = new ObjectLoader("Model");
object user = loader.CreateInstance("UserInfo");
Console.WriteLine($"實例: {user.GetType().FullName}");

foreach (var p in loader.GetProperties(user))
    Console.WriteLine($"{p.PropertyType.Name} {p.Name}");

loader.SetProperty(user, "UserId", 1);
loader.SetProperty(user, "UserName", "admin");
Console.WriteLine($"UserId: {loader.GetProperty(user, "UserId")}");
Console.WriteLine($"UserName: {loader.GetProperty(user, "UserName")}");

loader.InvokeMethod(user, "Show");
// 輸出: UserId:1, UserName:admin

進階:InvokeMember 統一調用入口

`Type.InvokeMember` 可綁定標志一次完成創建、調用、屬性/字段讀寫。

Type type = typeof(Love);
object obj = type.InvokeMember(null, 
    BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
    null, null, null);

// 調用方法
type.InvokeMember("Display", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,
    null, obj, new object[] { "hello" });

// 設置屬性
type.InvokeMember("Name", BindingFlags.SetProperty, null, obj, new object[] { "abc" });

// 讀取屬性
string name = (string)type.InvokeMember("Name", BindingFlags.GetProperty, null, obj, null);

// 設置字段
type.InvokeMember("field1", BindingFlags.SetField, null, obj, new object[] { 444 });

// 讀取字段
int val = (int)type.InvokeMember("field1", BindingFlags.GetField, null, obj, null);

實戰:DataTable 轉實體列表 (簡易 ORM 核心)

public static class DataTableMapper
{
    public static List<T> ToList<T>(this DataTable table) where T : new()
    {
        var loader = new ObjectLoader(typeof(T).Assembly.GetName().Name);
        var list = new List<T>();
        var props = typeof(T).GetProperties()
            .Where(p => p.CanWrite)
            .ToDictionary(p => p.Name, p => p);

        foreach (DataRow row in table.Rows)
        {
            T entity = new T();
            foreach (DataColumn col in table.Columns)
            {
                if (props.TryGetValue(col.ColumnName, out var prop) 
                    && row[col] != DBNull.Value)
                {
                    // 類型轉換處理
                    object value = row[col];
                    if (prop.PropertyType != value.GetType())
                        value = Convert.ChangeType(value, prop.PropertyType);
                    prop.SetValue(entity, value);
                }
            }
            list.Add(entity);
        }
        return list;
    }
}

// 使用
var users = dataTable.ToList<UserInfo>();

BindingFlags 速查

標志含義
Public / NonPublic公共 / 非公共成員
Instance / Static實例 / 靜態成員
DeclaredOnly僅當前類型聲明,不含繼承
CreateInstance調用構造函數
InvokeMethod調用方法
GetProperty / SetProperty讀/寫屬性
GetField / SetField讀/寫字段

效能優化建議

  • 緩存 PropertyInfo[]、MethodInfo 避免重複反射
  • 高頻調用用 Delegate.CreateDelegate 轉為強類型委托
  • 大批量映射考慮 Expression.Compile() 生成委托
  • 避免在循環中反復 GetType()/GetProperty()

反射是框架級開發的基石,掌握動態創建、屬性映射、方法調用三板斧,即可構建屬於自己的微型 ORM 或插件容器。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved