IL中的ldsfld和ldstr有什么不同?

时间:2010-09-09 06:31:18

标签: .net cil

我已经阅读了一些关于String.Empty vs“”的文章,我也做了自己的测试。它们之间有所不同。

的String.Empty

L_0001: ldsfld string [mscorlib]System.String::Empty

“”

L_0001: ldstr ""

在与朋友交谈之后,他们争辩说String.Empty比“”更快,因为在引擎盖下(在汇编级别)ldstr比ldsfld多做1圈。 (我不记得使它们与众不同的步骤)

我想知道如何检查这方面的表现。

3 个答案:

答案 0 :(得分:13)

ldsfld操作将静态字段的值推送到评估堆栈,而ldstr推送对元数据字符串文字的引用。

性能差异(如果有的话)将是最小的。较新版本的编译器实际上将""替换为String.Empty

您还应该考虑代码的可读性和可维护性。使用String.Empty更清楚的是,你实际上是指一个空字符串而不是忘记在字符串文字中键入内容。

编辑:

我看了一下创建的本机代码。

C#3,发布模式,x86:

        string a = String.Empty;
0000002a  mov         eax,dword ptr ds:[0356102Ch]
0000002f  mov         dword ptr [ebp-8],eax
        string b = "";
00000032  mov         eax,dword ptr ds:[0356202Ch]
00000038  mov         dword ptr [ebp-0Ch],eax

C#3,发布模式,x64:

        string a = String.Empty;
0000003b  mov         rax,12711050h 
00000045  mov         rax,qword ptr [rax] 
00000048  mov         qword ptr [rsp+28h],rax 
        string b = "";
0000004d  mov         rax,12713048h 
00000057  mov         rax,qword ptr [rax] 
0000005a  mov         qword ptr [rsp+30h],rax 

所以,最后代码是相同的。

答案 1 :(得分:7)

ldstr是IL从元数据加载特定的字符串标记。

ldsfld是IL加载指定的字段 - 在本例中为string.Empty

换句话说,它们是完全不同的操作,在这种情况下碰巧具有相同的结果。它们是如何在装配层面实施的?那么,这很可能取决于您正在使用的CLR的版本。问你的朋友他们正在谈论哪个版本...桌面(32或64位?1,2,2SP1,2SP2,4?),Compact Framework(再次,哪个版本?),Silverlight(哪个操作系统,哪个版本) ?)他们是否在您实际讨论的代码上使用了cordbg,或者他们是否在某些示例代码上使用了代码,这些代码可能没有以相同的方式进行优化?

我会(并且有)争辩说你应该使用你觉得更具可读性的东西。我个人更喜欢"",但其他人更喜欢string.Empty。没关系。在性能原因上争论另一个需要证据虽然......理想情况下,证据基于您实际编写的代码,而不是微观基准。

我会惊讶看到代码,其中两者之间的任何差异实际上导致了实际代码中的显着性能差异 - 除了可能有更好的方法来接近任务的情况。

答案 2 :(得分:7)

从.NET 4.5中,差异 在这种情况下 是:完全没有。看起来JIT现在检测到这个ldsfld并直接注入interned空字符串。

你可以这样说,因为在< 4.5,你可以通过反射改变string.Empty的值,它会使用string.Empty影响代码。令人讨厌但可能。从4.5开始,这不再适用。如果你可以通过反射检查你得到黑客版本,但使用string.Empty通过ldsfld的代码获取正确的空字符串而不是被黑客攻击的版本。