C#是否优化字符串字面量的拼接?

61

例如,编译器是否知道如何转换

string s = "test " + "this " + "function";
string s = "test this function";

那么如何避免使用字符串拼接时的性能损耗呢?

7个回答

69
是的。这是由C#规范保证的。它在第7.18节(C# 3.0规范)中规定:
当一个表达式满足上述要求时,该表达式在编译时被计算。即使表达式是包含非常量结构的更大表达式的子表达式,这也是正确的。
(“上述要求”包括应用于两个常量表达式的+运算符。)
另请参见这个问题

2
这是否仍适用于插值字符串?我正在尝试理解C# 6规范(草案),但如果您不习惯阅读此类文档,则语言会相当混乱 :) - user247702
2
@Stijn:不,插值字符串字面量不是常量表达式。 - Jon Skeet
1
@JonSkeet 我知道整体上它们不同,但是$"hello {foo}, i'm {bar}"$"hello {foo}" + $"i'm {bar}"是一样的吗? - user247702
2
@Stijn:不,第二个会变成单独调用string.Format - Jon Skeet

27

关于相关主题的一则侧记——C#编译器也会使用'+'运算符对涉及非字面量的多次字符串连接进行“优化”,将其转换为对String.Concat()方法的多参数重载的单个调用。

因此,

string result = x + y + z;

编译成等效的内容

string result = String.Concat( x, y, z);

与其采用更为天真的可能性:

string result = String.Concat( String.Concat( x, y), z);

虽然没有什么惊天动地的,但我只是想在关于字符串字面量拼接优化的讨论中添加这一点。我不知道这种行为是否由语言标准规定。


11

是的。

C# 不仅优化字符串字面量的拼接,还将等效的字符串字面量折叠为常量,并使用指针引用所有对同一常量的引用。


5
这被称为“字符串驻留”,并且在《CLR via C#》一书中有详尽的介绍。 - FlySwat

8

是的 - 你可以使用ILDASM显式地看到这一点。

例如:

这是一个类似于你的示例程序,其后是已编译的CIL代码:

注意:我使用String.Concat()函数只是为了看看编译器如何处理两种不同的连接方法。

程序

class Program
{
    static void Main(string[] args)
    {
        string s = "test " + "this " + "function";
        string ss = String.Concat("test", "this", "function");
    }
}

ILDASM

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       29 (0x1d)
  .maxstack  3
  .locals init (string V_0,
           string V_1)
  IL_0000:  nop
  IL_0001:  ldstr      "test this function"
  IL_0006:  stloc.0
  IL_0007:  ldstr      "test"
  IL_000c:  ldstr      "this"
  IL_0011:  ldstr      "function"
  IL_0016:  call       string [mscorlib]System.String::Concat(string,
                                                              string,
                                                              string)
  IL_001b:  stloc.1
  IL_001c:  ret
} // end of method Program::Main

注意在IL_0001处编译器创建了常量"test this function",而不是像对待String.Concat()函数一样-为每个.Concat()参数创建常量,然后调用.Concat()函数。


6

消息来源:

连接是将一个字符串添加到另一个字符串末尾的过程。当您使用 + 运算符连接字符串字面量或字符串常量时,编译器会创建单个字符串。不会发生运行时的连接。但是,只有在运行时才能连接字符串变量。在这种情况下,您应该了解各种方法的性能影响。

http://msdn.microsoft.com/en-us/library/ms228504.aspx


3

我有一个类似的问题,但是关于VB.NET而不是C#。验证这一点最简单的方法是在Reflector下查看编译后的程序集。

答案是,C#和VB.NET编译器都优化字符串文字的连接。


2
我相信答案是肯定的,但你需要查看编译器输出的内容...只需编译并使用反射器即可 :-)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接