首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#到CIL Boxing与ToString的成本

C#到CIL Boxing与ToString的成本
EN

Stack Overflow用户
提问于 2015-03-11 19:30:03
回答 2查看 749关注 0票数 6

我正在通过C# (第4版)阅读“CLR”一书,不是作为C#的新手,而是作为一个懂语言的人,试图提高我对CLR的基本功能的理解。

无论如何,在本书中,在讨论值类型的装箱/取消装箱时,给出了一个示例(pg127-131),该示例的结尾是对Console.WriteLine的调用,并将值类型连接到作为参数传递的字符串。

这本书解释了装箱和取消装箱/复制操作会造成开销,我已经知道了这一点,但它随后指出,可以通过在传入的值类型上运行.ToString()来优化示例。

我创建了一个示例程序并编译了它,然后使用ILDASM检查它生成的IL。ToString的版本本质上是相同的,但是将"box“指令替换为对ToString的”调用“(没有震惊)。

我在一个100000次运行的循环中对代码进行了基准测试,没有差别(它波动于哪一个运行得更快)。我意识到,其他因素在基准测试(缓存等)中起作用,但顺便说一句,这本书解释说,即使是在一个幼稚的基准中,我也希望在避免使用“盒子”指令时会看到显著的不同。

仅仅是调用一个函数不是更好吗?在ToString中是否有一种拳击操作可以抵消这些好处,而这本书却是错的呢?有人能解释一下这件事吗?

以下是两个ILDASM读物,供参考:

代码语言:javascript
复制
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       24 (0x18)
  .maxstack  2
  .locals init (int32 V_0)
  IL_0000:  ldc.i4.4
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  box        [mscorlib]System.Int32
  IL_0008:  ldstr      "."
  IL_000d:  call       string [mscorlib]System.String::Concat(object,
                                                              object)
  IL_0012:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0017:  ret
} // end of method Program::Main
代码语言:javascript
复制
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       25 (0x19)
  .maxstack  2
  .locals init (int32 V_0)
  IL_0000:  ldc.i4.4
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  call       instance string [mscorlib]System.Int32::ToString()
  IL_0009:  ldstr      "."
  IL_000e:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_0013:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0018:  ret
} // end of method Program::Main
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-03-11 19:42:30

CLR可能会内联对string.Concat(object,object)的调用,这将产生与“优化”版本相同的代码。请注意,C#编译器将把许多这类优化留给CLR,因为它有更好的工具可供使用。

除了一对空检查(这将被优化出)之外,它只调用string.Concat(left.ToString(),right.ToString()),这将被简化为string.Concat(left,right.ToString()),因为CLR会看到ToString()只返回this

因此,在这两种情况下,执行的代码可能是相同的。

票数 5
EN

Stack Overflow用户

发布于 2015-03-11 19:41:13

您忽略了这样一个事实,即String.Concat将对提供的object参数在内部调用ToString

代码语言:javascript
复制
public static String Concat(Object arg0, Object arg1) {
    Contract.Ensures(Contract.Result<String>() != null);
    Contract.EndContractBlock();

    if (arg0 == null)
    {
        arg0 = String.Empty;
    }

    if (arg1==null) {
        arg1 = String.Empty;
    }
    return Concat(arg0.ToString(), arg1.ToString());
}

因此,call指令无论如何都会存在,但是它隐藏在Concat方法调用中。

调用ToString会选择不同的Concat重载,并且这个重载不会在内部调用ToString

代码语言:javascript
复制
IL_000d:  call       string [mscorlib]System.String::Concat(object, object)

代码语言:javascript
复制
IL_000e:  call       string [mscorlib]System.String::Concat(string, string)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28995660

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档