【问题标题】:Why is it possible to change the value of a readonly field but not of a const using reflection?为什么可以使用反射更改只读字段的值,但不能更改 const 的值?
【发布时间】:2013-03-17 07:57:46
【问题描述】:

为什么可以使用反射修改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)

【问题讨论】:

  • @CodyGray 感谢您的链接。我不知道为const 处理内存的方式以及它可能对其他程序集产生的影响。修改 const 的值可能会对我猜的其他程序集产生未知的影响。

标签: c# reflection


【解决方案1】:

因为const 字段在编译时“设置”,即编译器在编译期间用给定值替换const。由于const 值的工作方式,它们的值被复制到每个使用它们的程序集中。而readonly 字段是在运行时评估的。

【讨论】:

  • 当我在 ildasm 中查看我的问题中的代码时,readonly 字段的值也是在编译时设置的。与const 不同,不是在字段本身上,而是在构造函数中。所以我仍然不确定为什么一个可以“覆盖”而另一个不能。
  • @Guillaume 您能否更新您的问题以包括您对 const 和 readonly 的 IL 观察结果。
  • @Guillaume 在这种情况下,您可能会观察到编译器优化,它使您的 readonly 看起来与您的 const 声明相同。你不能从编译后的代码中推断出太多!
【解决方案2】:

原因是常量在编译时被替换为它的值。但只读字段不是。您可以在 declaraiotn 和/或该类的构造函数中为只读字段设置值。我希望这能回答你的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-06
    • 2012-02-03
    • 2010-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-26
    • 2019-06-20
    相关资源
    最近更新 更多