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

时间:2014-11-06 07:07:18

标签: c#

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

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

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

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

可能是一个菜鸟问题并且之前已被问过,但无法找到参考。

2 个答案:

答案 0 :(得分:14)

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编译不会在这里添加任何内容。原因是:功能可能有副作用。

答案 1 :(得分:5)

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

中捕获

修改 最初的问题只是关于“是吗?”,而不是“为什么?”,但仍然有几个评论和其他答案试图回答/演示“为什么?”。

对“为什么?”这么感兴趣?我正在编辑我的答案,陈述我的版本“为什么?”。 即如果您查看C# specification,对于任何相关方案,规范都会讨论capturing the variable .. capturing the expression。 这就是编译器行为方式的原因。因为规范中的不是。为什么它不在规范中,是C#设计团队可以回答的问题。如果考虑feature of capturing expressions,其余的是推测,部分或全部可能有或没有优点。