C#编译器非常智能,可以优化字符串与+运算符串联到String.Concat调用中.
以下代码:
var a = "one";
var b = "two";
var c = "three";
var d = "four";
var x = a + b + c + d;
Run Code Online (Sandbox Code Playgroud)
编译成这个IL:
IL_0000: ldstr "one"
IL_0005: stloc.0 // a
IL_0006: ldstr "two"
IL_000B: stloc.1 // b
IL_000C: ldstr "three"
IL_0011: stloc.2 // c
IL_0012: ldstr "four"
IL_0017: stloc.3 // d
IL_0018: ldloc.0 // a
IL_0019: ldloc.1 // b
IL_001A: ldloc.2 // c
IL_001B: ldloc.3 // d
IL_001C: call System.String.Concat
Run Code Online (Sandbox Code Playgroud)
编译器找出了正确的重载,String.Concat它需要4个参数并使用它.
F#编译器不这样做.相反,每个+都编译成一个单独的调用String.Concat:
IL_0005: ldstr "one"
IL_000A: ldstr "two"
IL_000F: call System.String.Concat
IL_0014: ldstr "three"
IL_0019: call System.String.Concat
IL_001E: ldstr "four"
IL_0023: call System.String.Concat
Run Code Online (Sandbox Code Playgroud)
显然这是因为在F#编译器中没有实现这种特殊的优化.
问题是为什么:技术上难以做到还是有其他原因?
字符串连接是一个相当常见的操作,虽然我意识到编译代码的性能不是首要任务,但我想这种优化在很多情况下都很有用.
我认为优化没有什么困难 - 我认为它没有实现的主要原因是它特定于字符串连接而不是更普遍的应用.但是,这听起来像是一个使用F#开源版本的有趣项目!
也就是说,即使是上面做的C#优化也不是那么聪明.没有理由为什么编译器不应该在它们是常量时直接连接字符串并产生:
IL_0000: ldstr "onetwothreefour"
Run Code Online (Sandbox Code Playgroud)
换句话说,在添加通常有用的东西和添加越来越多的特殊情况之间总是存在权衡 - C#编译器显然有一些与字符串连接相关的特殊情况......