如果一個類定義了一個Private的字段,在運行時,正常方式下,在類的外部當然是不能訪問這個字段,更談不上改變值了。但在特殊情況下,我們不能修改已有類的代碼,但又要去改變,怎麼辦?用反射。代碼是最好的表達語言:
/* 先定義一個測試類 */
public class TestClass {
private readonly int i1 = 10;
private const int i2 = 20;
private int i3 = 30;
private static int i4 = 40;
private static readonly int i5 = 50;
public void Print() {
Console.WriteLine("i1: " + i1.ToString());
Console.WriteLine("i2: " + i2.ToString());
Console.WriteLine("i3: " + i3.ToString());
Console.WriteLine("i4: " + TestClass.i4.ToString());
Console.WriteLine("i5: " + TestClass.i5.ToString());
Console.WriteLine();
}
}
/* 反射方法修改類的私有字段值 */
class Program {
static void Main(string[] args) {
TestClass tc = new TestClass();
Type type = typeof(TestClass);
tc.Print();
// 只讀字段,可通過反射方式修改值
FieldInfo fi = type.GetField("i1", BindingFlags.NonPublic | BindingFlags.Instance);
fi.SetValue(tc, (int)fi.GetValue(tc) + 1);
// 常量字段,反射也無法修改,如果取消下面語句的註釋,執行會出錯。
/* 原因說明:常量的值必須在編譯時就確定(只能是基元類型),也就是說在定義時就賦值。
編譯後常量的值是保存在程序集的元數據中,在運行時是不可修改的;
而其它字段是存儲在動態內存中,在運行時是可修改的。*/
fi = type.GetField("i2", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
//fi.SetValue(null, (int)fi.GetValue(null) + 1);
// 正常字段,當然可以修改
fi = type.GetField("i3", BindingFlags.NonPublic | BindingFlags.Instance);
fi.SetValue(tc, (int)fi.GetValue(tc) + 1);
// 靜態字段,也可修改
fi = type.GetField("i4", BindingFlags.NonPublic | BindingFlags.Static);
fi.SetValue(null, (int)fi.GetValue(null) + 1);
// 靜態只讀字段,下面代碼不出錯,改變了反射字段的值,但類中的字段值並沒有被改變
fi = type.GetField("i5", BindingFlags.NonPublic | BindingFlags.Static);
fi.SetValue(null, (int)fi.GetValue(null) + 1);
int i5 = (int)fi.GetValue(null); // i5 得到值爲 51
tc.Print();
Console.WriteLine("i5: " + i5.ToString());
Console.ReadKey();
}
}
下面是輸出結果:
i1:10
i2:20
i3:30
i4:40
i5:50
i1:11
i2:20
i3:31
i4:41
i5:50
i5:51