例如,在Javascript中,强烈建议人们在循环之外放置函数调用以获得更好的性能:
var id = someIdType.ToString();
someList.Where(a => a.id == id) ...
C#怎么样?同样的情况还是编译器/运行时使用内部优化/缓存?
someList.Where(a => a.id == someIdType.ToString()) ...
可能是一个菜鸟问题并且之前已被问过,但无法找到参考。
答案 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
,其余的是推测,部分或全部可能有或没有优点。