5

如果我有

private string Foo(string decrypted)
{
    return decrypted.Substring(blah);
}

private string Foo(string decrypted)
{
    string s = decrypted.Substring(blah);
    return s;
}

这是一样的吗?编译器可以删除s吗?

怎么样

private string Foo(string decrypted)
{
    string s = decrypted.Substring(blah);
    string t = s;
    return t;
}

?

谢谢。

4

2 回答 2

4

我很好奇,所以我试了一下(使用 LINQPad 4 进行优化)。这就是我得到的:

private string Foo(string decrypted)
{
    return decrypted.Substring(0);
}
Foo:
IL_0000:  ldarg.1     
IL_0001:  ldc.i4.0    
IL_0002:  callvirt    System.String.Substring
IL_0007:  ret        

private string Foo(string decrypted)
{
    string s = decrypted.Substring(0);
    return s;
}
Foo:
IL_0000:  ldarg.1     
IL_0001:  ldc.i4.0    
IL_0002:  callvirt    System.String.Substring
IL_0007:  stloc.0     // s
IL_0008:  ldloc.0     // s
IL_0009:  ret     

private string Foo(string decrypted)
{
    string s = decrypted.Substring(0);
    string t = s;
    return t;
}
Foo:
IL_0000:  ldarg.1     
IL_0001:  ldc.i4.0    
IL_0002:  callvirt    System.String.Substring
IL_0007:  stloc.0     // s
IL_0008:  ldloc.0     // s
IL_0009:  stloc.1     // t
IL_000A:  ldloc.1     // t
IL_000B:  ret    

看来编译器没有优化,s或者t,但是,我怀疑 JIT 解释器会。

于 2013-06-11T13:09:35.050 回答
1

在我看来,问题基本上是“C# 编译器是否支持命名返回值优化(NRVO)?”

我想这是一个合理的问题,但就像delnan 指出的那样,它并不是特别相关,因为 C# 中的字符串是引用类型。如果您是 C++ 程序员,您可以认为引用类型本质上等同于指针。因此,尽管您按值返回字符串,但实际上您只是按值返回引用,而不是对象本身。就像您按值返回指针地址一样。不需要制作整个字符串对象的副本,因此优化对您的好处很少。您需要 NRVO 的唯一原因是避免遭受大而昂贵的副本的性能损失,但复制指针/引用并不昂贵。

但是,如果您给出了一个使用值类型而不是引用类型(例如,大型结构)的不同示例,那么通过实施 NRVO 可能会获得显着的性能改进。不幸的是,即使在这种情况下,我也不相信 C# 编译器会这样做。我想 JITer 可能会;我不能肯定地说。(如果现在不这样做,它总是可以在未来的版本中添加。虽然在 C# 代码中很少发现这么大的结构,所以这不太可能在性能团队的目标列表的顶部。)

有关更多详细信息,推荐阅读 Jon Skeet 关于C# 中的引用和值的文章。

于 2013-06-11T13:47:44.197 回答