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? .

4

3 回答 3

19

同样,化学定律说,任何反应都不能导致一种元素的原子变成另一种元素的原子,但物理定律说它一直在发生。化学是物理学的一个受限制的子集,以便将问题简化为更可解决的方式。

在这种情况下,反射是物理学,而正常的编程是化学。它以更简单的心态运作。反射允许您规避那组更简单的规则,使您面临新的流程,但也面临新的危险。

于 2012-08-30T16:09:11.340 回答
5

因为readonly,就像private,防范墨菲,而不是马基雅维利*。

我们使用readonlyandprivate和其他任何限制我们可以做的事情,主要是因为我们希望限制更多不正确、不一致或只是简单愚蠢的事情,而不是我们拥有有用和富有成果的事情。

但它仍然只是一个和零。如果某些内存设置为数字“42”并且我们通过只读字段访问它,则在创建对象时它不是只读的。没有什么能阻止它被改变,除了编译器发现“嘿,首先你说你不想改变它,现在你试图改变它,什么给出了?这两个决定之一肯定是错误的”。

现在,没有保证反射能够改变它,但也没有保证它不会。现在,反射的工作方式和只读的工作方式意味着你可以改变它。至少,要阻止那些可能因为认为自己已经这样做而费心去做这件事的人,需要做很多工作(也许成本会影响我们的用户以及需要实施这项工作的团队)一个很好的理由。

请注意,与反射相关的权限确实阻止了马基雅维利,

*严格地说,墨菲是在谈论我们应该如何设计东西来阻止人们意外地做出灾难性的事情——这readonly是一个很好的例子,不能以错误的方式插入更好的插头——而马基雅维利是在教而不是练习技巧。不过,它远不如简明扼要的说法。

于 2012-08-30T17:15:04.670 回答
0

这是可能的,因为 .Net 中的反射是以这种方式实现的。我只能猜测这样做的动机,但它是一个强大(但缓慢)的工具,提供了极大的灵活性和滥用的可能性。

这不是实现这种改变的唯一方式,但这种讨论与任何进一步的主观猜测一样,都是题外话和格格不入的。

于 2012-08-30T16:24:37.513 回答