封裝是物件導向核心原則,私有成員原則上不應被外部存取。最佳實務是透過公開屬性暴露:
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
但實務上常遇到:只有 DLL 無原始碼、維護遺留系統原始碼遺失、單元測試需驗證內部狀態等情境。.NET 反射機制提供合法管道存取非公用成員。
關鍵旗標:BindingFlags.Instance | BindingFlags.NonPublic 指定搜尋條件為「實例非公用成員」。
將反射邏輯封裝為擴充方法,使用泛型強型別回傳:
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);
}
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);
}
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);
}
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);
}
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#中訪問私有成員
