【问题标题】:Does C# optimize the concatenation of string literals?C# 是否优化了字符串文字的连接?
【发布时间】:2010-09-22 06:34:17
【问题描述】:

例如,编译器是否知道翻译

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

string s = "test this function";

从而避免字符串连接对性能的影响?

【问题讨论】:

    标签: c# .net performance optimization


    【解决方案1】:

    是的。这是由 C# 规范保证的。它在(C# 3.0 规范的)第 7.18 节中:

    每当一个表达式满足 上面列出的要求, 表达式在 编译时。这是真的,即使 表达式是 a 的子表达式 更大的表达式,包含 非常量构造。

    (“上面列出的要求”包括应用于两个常量表达式的 + 运算符。)

    另见this question

    【讨论】:

    • 介意我把问题改成 C# 吗?
    • 知道这是否仍然适用于插值字符串?我正在尝试理解 C# 6 规范的(草稿),但如果您不习惯阅读此类文档,该语言会非常令人困惑 :)
    • @Stijn:不,内插字符串文字不是常量表达式。
    • @JonSkeet 我知道他们不是,但是$"hello {foo}, i'm {bar}"$"hello {foo}" + $"i'm {bar}" 一样吗?
    • @Stijn:不,在第二个中,您最终会单独调用string.Format
    【解决方案2】:

    我相信答案是肯定的,但是您必须查看编译器吐出的内容...只需编译并在其上使用反射器 :-)

    【讨论】:

      【解决方案3】:

      是的。

      C# 不仅优化了字符串字面量的串联,它还把等价的字符串字面量折叠成常量,并使用指针来引用同一个常量的所有引用。

      【讨论】:

      • 它被称为“String Interning”,在 CLR by C# 一书中有深入介绍。
      【解决方案4】:

      来自马口:

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

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

      【讨论】:

        【解决方案5】:

        只是一个相关主题的旁注 - C# 编译器还将使用“+”运算符“优化”涉及非文字的多个连接,以对 String.Concat( ) 方法。

        所以

        string result = x + y + z;
        

        编译成等价于

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

        而不是更天真的可能性:

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

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            【解决方案7】:

            是的 - 您可以使用 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 是如何创建常量“测试此函数”的,而不是编译器如何处理 String.Concat() 函数 - 它为每个 .Concat() 参数创建一个常量,然后调用 . Concat() 函数。

            【讨论】:

              猜你喜欢
              • 2010-09-22
              • 2017-06-10
              • 2011-05-16
              • 1970-01-01
              • 1970-01-01
              • 2011-06-12
              • 1970-01-01
              • 2017-03-09
              相关资源
              最近更新 更多