C#是否自动优化循环/lambda语句中的代码

本文关键字:语句 lambda 代码 循环 是否 优化 | 更新日期: 2023-09-27 18:29:24

例如,在Javascript中,强烈建议将函数调用放在循环之外以获得更好的性能:

var id = someIdType.ToString();
someList.Where(a => a.id == id) ...

C#怎么样?同样的情况还是编译器/运行时采用了内部优化/缓存?

someList.Where(a => a.id == someIdType.ToString()) ...

可能是一个noob问题,以前也被问过,但找不到参考资料。

C#是否自动优化循环/lambda语句中的代码

C#代码:

List<string> list = new List<string>();
list.Where(a => a == typeof(String).ToString());

MSIL中的Lambda表达式,调试配置:

.method private hidebysig static bool  '<Main>b__0'(string a) cil managed
{
  .custom instance void     [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init ([0] bool CS$1$0000)
  IL_0000:  ldarg.0
  IL_0001:  ldtoken    [mscorlib]System.String
  IL_0006:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_000b:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0010:  call       bool [mscorlib]System.String::op_Equality(string,
                                                             string)
  IL_0015:  stloc.0
  IL_0016:  br.s       IL_0018
  IL_0018:  ldloc.0
  IL_0019:  ret
} // end of method Program::'<Main>b__0'

MSIL中的Lambda表达式,发布配置:

.method private hidebysig static bool  '<Main>b__0'(string a) cil managed
{
  .custom instance void     [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       22 (0x16)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldtoken    [mscorlib]System.String
  IL_0006:  call       class [mscorlib]System.Type     [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_000b:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0010:  call       bool [mscorlib]System.String::op_Equality(string,
                                                             string)
  IL_0015:  ret
} // end of method Program::'<Main>b__0'

两个版本都调用typeof(String).ToString()),每次迭代都会调用此lambda。没有IL级别的优化,JIT编译不会在这里添加任何内容。原因是:功能可能有副作用。

将为列表中的每个元素执行lambda。。因此,代码someIdType.ToString()将针对每个元素执行。我不认为编译器或运行时会为您缓存它。(AFAIK someIdType将在闭合中捕获,但不会捕获.ToString()

编辑:最初的问题只是关于"Do?",而不是关于"Why?",但仍然有一些评论和其他答案试图回答/证明"Why"。

鉴于人们对"为什么?"如此感兴趣,我正在编辑我的答案,以陈述我对"为什么"的看法。即,如果您查看C#规范,对于任何相关场景,该规范都会讨论capturing the variable而不是capturing the expression。这就是编译器的行为方式的原因。。因为它在规范中不是。为什么它不在规范中,这是C#设计团队可以回答的问题。。其余部分是推测,如果考虑feature of capturing expressions,其部分或全部可能有价值,也可能没有价值。