如果一个类定义了一个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