为什么可以readonly
使用反射修改字段的值,但不能修改 a 的值const
?
class Program
{
static void Main(string[] args)
{
Foobar foobar = new Foobar();
Console.WriteLine(foobar.foo); // Outputs "Hello"
Console.WriteLine(Foobar.bar); // Outputs "Hello"
var field = foobar.GetType().GetField("foo");
field.SetValue(foobar, "World"); // Ok
field = foobar.GetType().GetField("bar");
field.SetValue(foobar, "World"); // Throws FieldAccessException
Console.ReadKey();
}
}
public class Foobar
{
public readonly string foo = "Hello";
public const string bar = "Hello";
}
我已经阅读了这个答案,所以我知道它可以违反规则,readonly
但为什么不const
这样做呢?我敢肯定有一个很好的理由,但我无法弄清楚它可能是什么。
- 编辑 -
当我使用 ildasm 查看上面的代码时,该readonly
字段的值是在编译时设置的。与类的构造函数不同,不是在字段本身上,const
而是在类的构造函数中。所以我不确定为什么一个可以被“覆盖”,而另一个不能。
我的意思是,即使const
二进制中的值是“硬编码”的,也是无法修改它的原因是框架本身的技术限制,因为“它已经设置”或只是一个设计决定。const
我看不出有什么理由不能在某处修改readonly
.
-- 编辑 2 --
加上已接受的答案,还有另一个非常有趣的答案。当我问这个问题时,我首先没有得到的是,后面的值const
实际上在代码中使用它的任何地方都被替换了。有了这个声明:
public const string Foo = "Hello";
稍后再写
Console.WriteLine(Foo);
相当于写
Console.WriteLine("Hello");
确实我的代码
Console.WriteLine(foobar.foo);
Console.WriteLine(Foobar.bar);
在 IL 中被替换为
IL_0008: ldfld string ConsoleApplication3.Foobar::foo
IL_000d: call void [mscorlib]System.Console::WriteLine(string)
IL_0012: nop
IL_0013: ldstr "Hello"
IL_0018: call void [mscorlib]System.Console::WriteLine(string)