Why can't I change the value of String.Empty?
虽然我知道改变String.Empty的值是个坏主意,但我不明白为什么我不能这样做。
要了解我的意思,请考虑以下课程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class SomeContext
{
static SomeContext (){}
public static readonly string Green ="Green";
public static readonly SomeContext Instance = new SomeContext ();
private SomeContext (){}
public readonly string Blue ="Blue";
public static void PrintValues ()
{
Console .WriteLine(new { Green, Instance .Blue, String.Empty }.ToString());
}
} |
我有一个小的控制台应用程序试图操作这三个只读字段。它可以成功地将蓝色和绿色变为粉红色,但空的保持不变:
1 2 3 4 5 6 7
| SomeContext .PrintValues();
/// prints out : { Green = Green, Blue = Blue, Empty = }
typeof(SomeContext ).GetField("Blue").SetValue(SomeContext .Instance, "Pink");
typeof(SomeContext ).GetField("Green", BindingFlags .Public | BindingFlags .Static).SetValue(null, "Pink");
typeof(String).GetField("Empty", BindingFlags .Public | BindingFlags .Static).SetValue(null, "Pink");
SomeContext .PrintValues();
/// prints out : { Green = Pink, Blue = Pink, Empty = } |
为什么?
最初,我还问为什么String.Empty不是一个常数。我在另一篇文章中找到了问题的这一部分的答案,并删除了问题的那一部分)。
注意:没有一个"副本"对这个问题有决定性的答案,这就是我问这个问题的原因。
- 你的评论是绿色=打印输出中的绿色…在实际的打印输出中,它实际上说了什么,特别是如果您确定要查找两个粉红色或不粉红色的实例。
- 这可能部分地回答了您的问题:stackoverflow.com/questions/507923/…
- 这可以回答以下问题:stackoverflow.com/questions/16618302/…
- 很高兴找到@amy,我相信这正是我们要说的!
- @艾米-这很有帮助,肯定提供了很多背景信息。我还是不太清楚为什么,因为那篇文章上没有真正的答案。我将按照此处引用的链接查看它是否会引导我找到实际答案。
- 还有这个旧问题的副本stackoverflow.com/q/6293924/103167,特别是对这个答案的评论stackoverflow.com/a/6297265/103167
- 让我们看看这次是否会出现deus ex machina(也称为@eric lippert)。
- 当然,有些问题也有相似之处,但由于其他问题都没有答案,如果你们能让这个问题保持足够长的时间,让有知识的人有机会回答,我将不胜感激。
- @Benvoigt-看到你对JIT优化的评论。这是我怀疑的,但你知道这是肯定的吗?
- @聪明人:我知道JIT这样做是合法的。我知道我见过一些JIT版本(单声道),在某些情况下是这样的。要知道在您的情况下JIT是否会这样做,您应该反汇编JIT生成的机器代码。
- 简短回答:您正在更改System.String.Empty。问题是,检查System.String.Empty的当前值的代码已经损坏,因为您违反了它的不变量。开始违反系统不变量,什么都不能依赖。
- @本沃伊特-我已经思考了来源,我没有看到任何地方,在那里,MdFieldInfo.GetValue(...)或RtFieldInfo.GetValue(...)依赖String.Empty。你有没有特别的地方想让我失踪?
- 我注意到Getvalue返回"pink",尽管访问字段返回
- @本沃伊特-我从来没有低于伊尔。你能给我指出一个方向,在那里我可以学会如何分解和解释机器代码,以便我自己检查一下吗?
- @sriramsakthivel-+1,很有趣。这似乎也可以理解Benvoigt关于JIT优化的说法。
- 看看我该如何引起人们对那些未回答的老问题的关注。如果你发现有一个问题没有回答,解决方法就是不要再问了。考虑在重复的帖子上贴一张赏金。
- @服务-问题是我觉得任何老问题都不能让问题变得清晰。只是看看他们的头衔。
- 为了突出你的观点,请不要使用大文本。不受欢迎。元评论通常应该保存在评论中,或者当评论太多的时候,转移到元评论中。它应该被排除在问题之外。
- @乔治斯托克-这是一个公平的妥协吗?
- @聪明的穴居人不会说谎,但CLR会说谎。
- @然后,聪明的穴居人编辑他们的标题,以更好地澄清他们所问的问题。
- 使用FieldInfo.GetValue返回String.Empty的设定值,即使String.Empty本身没有。clr是否在内存中缓存该值?
- @服务-他们问题的意图是不同的。这三个部分讨论相同的基本代码行。但是,每个问题都有不同的原因。如果我把他们的问题改成我的问题,我会歪曲他们的问题。看看他们,告诉我你是否有不同的想法。
- @艾米-没有真正的方法知道。归结为RuntimeFieldHandle.GetValue(...),即extern。但是我在去那里的路上没有看到任何缓存
- @SmartCaveman副本正在询问.NET 4.5中的行为为什么发生了变化。你在问它为什么会这样做(没有意识到它是4.5特有的)。回答那个问题会完全回答你的问题。你不需要把他们的问题变成你的问题。如果你觉得他们的问题标题不能有效地代表他们提出的问题,你可以编辑它们来改进。
- @Servy,那绝对是最近的。但是还有一个问题,那就是有一个选定的答案,根本不能回答我的问题。毫无疑问,他们是有关联的,但是如果那篇文章的答案足以回答OP的问题,那么我们就没有办法得到同样的答案。
- @聪明的穴居人,然后我请你回到我之前的评论。如果你想得到比问题更好的答案,那就发个赏金,而不是重复的问题。
- Servy,更好?
- @SmartCaveman:我刚刚改进了最古老问题的答案,以涵盖所有这些相关问题。
您不能更改它,因为您的计算机上有.NET 4.5。只需将项目的框架目标设置更改为3.5,就可以看到它起作用了。
clr具有string.empty的内置知识。例如,您将看到System.String类从未初始化它的反射器或引用源。它是在clr启动期间完成的。4.5如何阻止修改的可见是有点难说的。您实际上修改了字段,只需添加以下代码行:
1 2 3
| var s = typeof(String).GetField("Empty",
BindingFlags .Public | BindingFlags .Static).GetValue(null);
Console .WriteLine(s ); |
你会看到"粉色"。我猜它被抖动截获了。不过,我不能提供确凿的证据。有一个先例,尝试修补decimal.maxvalue,例如,另一个只读静态值。在3.5中也不可更改,抖动识别它并直接生成值而不读取字段。
我刚发现你对另一个主题完全相同的问题慷慨相助。280Z28的职位很相似。
- +1-谢谢您-您能建议一种方法来寻找有关正在进行的JIT优化的确凿证据吗?在注释中讨论了这一点,我得到的是需要分解JIT生成的机器代码。不幸的是,我不知道如何访问低于IL级别的任何内容。我不是要求有一个深入的解释,但朝着正确的方向轻轻一推会非常感激。
- 我完全不清楚为什么这个问题需要解决。反汇编并不能让您到达任何地方,您将看到抖动产生的原始地址正在被使用。它不会告诉你更多你已经知道的东西,它指向一个空字符串。您将需要v4.5抖动源代码,除非您在Microsoft申请作业,否则无法获取它。
- 汉斯,你显然是一个非常聪明的人,对软件有着深刻而广泛的理解。你是否只通过研究那些有直接实际利益的问题而获得了这种理解?或者,你会说,你偶尔经历过一些真正的激情,为了学习事物是如何工作的,而仅仅是为了学习事物是如何工作的,而沉溺于这种动力是达到你的专业水平的一个促成因素?