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

C# 反射實戰:優雅地存取私有成員(欄位、屬性、方法)

     編輯:關於C語言

前言:為何需要存取私有成員?

封裝是物件導向核心原則,私有成員原則上不應被外部存取。最佳實務是透過公開屬性暴露:

private string _name;
public string Name 
{ 
    get { return _name; } 
    set { _name = value; } 
}

但實務上常遇到:只有 DLL 無原始碼、維護遺留系統原始碼遺失、單元測試需驗證內部狀態等情境。.NET 反射機制提供合法管道存取非公用成員。

核心技術:BindingFlags 與反射 API

關鍵旗標:BindingFlags.Instance | BindingFlags.NonPublic 指定搜尋條件為「實例非公用成員」。

擴充方法實作:優雅的統一介面

將反射邏輯封裝為擴充方法,使用泛型強型別回傳:

1. 取得私有欄位值

public static T GetPrivateField<T>(this object instance, string fieldName)
{
    var flag = BindingFlags.Instance | BindingFlags.NonPublic;
    var type = instance.GetType();
    var field = type.GetField(fieldName, flag);
    return (T)field.GetValue(instance);
}

2. 取得私有屬性值

public static T GetPrivateProperty<T>(this object instance, string propertyName)
{
    var flag = BindingFlags.Instance | BindingFlags.NonPublic;
    var type = instance.GetType();
    var prop = type.GetProperty(propertyName, flag);
    return (T)prop.GetValue(instance, null);
}

3. 設定私有欄位值

public static void SetPrivateField(this object instance, string fieldName, object value)
{
    var flag = BindingFlags.Instance | BindingFlags.NonPublic;
    var type = instance.GetType();
    var field = type.GetField(fieldName, flag);
    field.SetValue(instance, value);
}

4. 設定私有屬性值

public static void SetPrivateProperty(this object instance, string propertyName, object value)
{
    var flag = BindingFlags.Instance | BindingFlags.NonPublic;
    var type = instance.GetType();
    var prop = type.GetProperty(propertyName, flag);
    prop.SetValue(instance, value, null);
}

5. 呼叫私有方法

public static T CallPrivateMethod<T>(this object instance, string methodName, params object[] parameters)
{
    var flag = BindingFlags.Instance | BindingFlags.NonPublic;
    var type = instance.GetType();
    var method = type.GetMethod(methodName, flag);
    return (T)method.Invoke(instance, parameters);
}

完整測試範例

測試類別庫

public class TestClass
{
    public TestClass()
    {
        privateField1 = 1;
        privateField2 = 99;
        PrivatePropertyA = "Lo";
        PrivatePropertyB = "ve";
    }

    private int privateField1;
    private int privateField2;
    private string PrivatePropertyA { get; set; }
    private string PrivatePropertyB { get; set; }

    private int Add() => privateField1 + privateField2;
    private string Join() => PrivatePropertyA + PrivatePropertyB;
}

主控台應用程式測試

var obj = new TestClass();

Console.WriteLine("私有欄位:");
Console.WriteLine(obj.GetPrivateField<int>("privateField1"));  // 1
Console.WriteLine(obj.GetPrivateField<int>("privateField2"));  // 99

Console.WriteLine("私有屬性:");
Console.WriteLine(obj.GetPrivateProperty<string>("PrivatePropertyA"));  // Lo
Console.WriteLine(obj.GetPrivateProperty<string>("PrivatePropertyB"));  // ve

Console.WriteLine("私有方法:");
Console.WriteLine(obj.CallPrivateMethod<int>("Add", null));  // 100
Console.WriteLine(obj.CallPrivateMethod<string>("Join", null));  // Love

Console.WriteLine("修改私有屬性後:");
obj.SetPrivateProperty("PrivatePropertyA", "hello");
obj.SetPrivateProperty("PrivatePropertyB", "world");
Console.WriteLine(obj.CallPrivateMethod<string>("Join", null));  // helloworld

Console.Read();

執行結果

執行結果輸出

注意事項與最佳實務

  • 效能考量:反射較直接呼叫慢,避免在高頻迴路中使用
  • 安全性:需 ReflectionPermission,部分信任環境可能受限
  • 維護風險:成員名稱硬編碼,重構時易出錯,建議搭配 nameof 或常數定義
  • 道德準則:僅在必要時(測試、相容、除錯)使用,勿濫用破壞封裝

原文參考

原文:C#中訪問私有成員

相關推薦

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