设置只读字段(这是一个错误吗?)

10

在只是尝试使用c#时,我发现了一件奇怪的事情。

这里是代码:

class Program
{
    static void Main(string[] args)
    {
        System.Diagnostics.Debug.Write(string.Empty);

        typeof(string)
            .GetField("Empty", BindingFlags.Static | BindingFlags.Public)
            .SetValue(null, "Tolgahan");


        Console.WriteLine(string.Empty);

        // output : Tolgahan
    }
}
为什么反射让我们改变只读字段?
该问题是“为什么允许使用反射进行设置”,而不是“如何做到这一点”,因此它不是Can I change a private readonly field in C# using reflection?的重复。

5
使用反射,你可以做许多平常做不到的事情。比如说,你可以获取/设置其他类中的私有字段。我几乎确定这不是一个bug;至于它是否可取,那另说了。 - Servy
4
引用一句话,readonly的作用是保护免受“墨菲,而不是马基雅维利”的影响。 - Damien_The_Unbeliever
@Dennis:另一个问题只是问是否可能,而这个问题则说明了它是可能的,但是问了为什么(因此在我看来比另一个问题更有价值)。 - O. R. Mapper
@O.R.Mapper:请仔细查看Eric Lippert的评论,那里有解释。 - Dennis
不想挑刺,但是...你在问关于只读字段的问题,但是你的例子是关于静态字段的。不过这个问题仍然是有效的。 - Arjen de Mooij
显示剩余2条评论
3个回答

19

同样地,化学定律表明没有反应可以使一个元素的原子变成另一个元素的原子,但是物理定律却经常发生这种情况。为了将问题简化为更易解决的方式,化学只是物理的一部分。

在这种情况下,反射就是物理学,而正常的编程则是化学。它以更简单的思维方式运作。反射允许您绕过这个更简单的规则集,让您接触到新的流程,但也会带来新的危险。


4
多么奇怪的隐喻。“不,这不是一个漏洞”就足够了,或者这个说法过于科技化吗? - Jodrell
4
试着用布莱恩·克兰斯顿的声音来读它,它突然就有意义了。 - Sedat Kapanoglu
@ssg 至少比Aaron Paul更有意义 :-) - corsiKa
我会选择卡尔·萨根 :) - Paul Groke

5
因为像private一样,readonly是为了防止Murphy而不是Machiavelli*。我们使用readonly、private和其他限制我们所能做的任何东西,主要是因为我们希望限制更多的错误、不一致或者只是纯粹愚蠢的事情,而不是有用且富有成果的事情。但它仍然只是0和1。如果一些内存被设置为数字“42”,并且我们通过一个readonly字段来访问它,那么当对象被创建时它就不是readonly的。除了编译器发现“嘿,你首先说你不想改变它,现在你正在尝试改变它,怎么回事?这两个决定中必须有一个是错误的"之外,没有什么可以阻止它被改变的。现在,关于反射是否能够改变它没有承诺,但也没有承诺不能改变它。目前,反射的工作方式和readonly的工作方式意味着你可以改变它。至少,这需要大量工作(可能会影响到我们用户以及需要实施这项工作的团队的成本),才能阻止那些认为自己有充分理由去麻烦做这件事情的人。注意,与反射相关的权限确实可以阻止Machiavelli,

*严格来说,Murphy是在讨论我们应该如何设计东西以防止人们意外地做出灾难性的事情——readonly就是一个很好的例子,而不能反插的插头则更好——而Machiavelli则是在教导而不是实践技巧。然而,这并没有那么简洁。


@p.s.w.g 是属于墨菲和马基雅维利的哪一类?我不能自己拍胸脯说这是我的功劳。我所知道的最早类似的用法(关于 C++ 中的 private)是由 Bjarne Stroustrup 提出的,尽管我不知道他是否是第一个这样做的人。 - Jon Hanna

0

这是因为在.Net中,Reflection是以这种方式实现的。我只能猜测其动机,但它是一个强大(但慢速)的工具,提供了巨大的灵活性和潜力,但也容易被滥用。

这不是唯一可以实现这种修改的方法,但这些讨论都是离题和不合适的,就像任何进一步的主观猜测一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接