为什么可以使用反射修改 readonly
字段的值而不是 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";
}
我读过 this answer所以我知道可以违反 readonly
的规则,但在那种情况下为什么不能违反 const
的规则?我确定有一个很好的理由,但我不知道它可能是什么。
-- 编辑--
当我使用 ildasm 查看上面的代码时,readonly
字段的值是在编译时设置的。与 const
不同,不是在字段本身上,而是在类的构造函数中。所以我不确定为什么可以“覆盖”一个而不是另一个。
我的意思是,即使 const
的值在二进制文件中是“硬编码”的,但无法修改它的原因是框架本身的技术限制,因为“它已经设置”或只是一个设计决定。我看不出有什么理由不能在某处修改 const
,因为它是为 readonly
做的。
-- 编辑 2 --
要加到已接受的答案中,还有 this other answer这很有趣。在问这个问题时,我首先没有得到的是 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)
最佳答案
因为 const
字段是在编译时“设置”的,即编译器在编译期间将 const
替换为给定值。由于 const
值的工作方式,它们的值被复制到每个使用它们的程序集中。而 readonly
字段在运行时进行评估。
关于c# - 为什么可以使用反射更改只读字段的值而不是 const 的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15458694/