当使用非常简单的表达式作为键来创建带Enumerable.ToLookup<TSource, TKey> Method (IEnumerable<TSource>, Func<TSource, TKey>)
的ILookup时,我可以使用lambda表达式:
var lk = myItems.ToLookup((x) => x.Name);
或本地功能:
var lk = myItems.ToLookup(ByName);
string ByName(MyClass x)
{
return x.Name;
}
我很好奇这个简单案例是否存在差异。
在his answer到Local function vs Lambda C# 7.0 SO用户svick提供了一个很好的论据 - 为什么 - 通用 - 本地函数比lambdas更好。
重要的一点是绩效差异:
创建lambda时,必须创建一个委托,在这种情况下这是一个不必要的分配。本地函数实际上只是函数,不需要委托。
但是,由于我们将其传递给ToLookup()
,无论如何都会创建一个委托。性能是否还有差异?
我可以想象编译器必须为myItems.ToLookup的每次调用创建一个新的委托lambda,而本地方法只需要一个委托实例;这是真的吗?
svick's answer中性能的第二个不同点是捕获变量和创建闭包:
此外,本地函数在捕获局部变量时更有效:lambdas通常将变量捕获到类中,而本地函数可以使用struct(使用ref传递),这又避免了分配。
但是,由于表达式不使用外部作用域中的变量,因此stated和Reed Copsey expanded不需要Eric Lippert作为闭包。回答Are Lambda expressions in C# closures?:
lambda可以使用闭包实现,但它本身不一定是闭包。 - Reed Copsey
[...]
可以被视为对象的函数只是一个委托。使lambda成为闭包的原因是它捕获了它的外部变量。 - Eric Lippert
这有点矛盾Eric Lippert他自己是answer到Assigning local functions to delegates Eric Lippert将本地函数解释为名为lambda:
本地函数基本上只是一个带有关联名称的lambda。
但是,这是一个较小的技术细节,对于做的lambda / local函数的代理来捕获外部范围变量。
这个简单的表达式不是递归的,不是泛型的,也不是迭代器。看起来更好的是一个意见问题 那么,简单的非捕获,非递归,非泛型和非迭代器lambda表达式和本地函数之间的性能(或其他)是否有任何差异?
答案 0 :(得分:5)
使用当前版本的编译器(Roslyn 2.8.0),带有lambda的版本效率更高,因为它会缓存委托。
关注the IL of code that has your two samples in separate methods,这是有效的:
sealed class HelperClass
{
public static readonly HelperClass Instance = new HelperClass();
public static Func<MyClass, string> CachedDelegate;
internal string LambdaByName(MyClass x)
{
return x.Name;
}
internal string LocalFunctionByName(MyClass x)
{
return x.Name;
}
}
void Lambda(IEnumerable<MyClass> myItems)
{
var lk = myItems.ToLookup(HelperClass.CachedDelegate ??
(HelperClass.CachedDelegate =
new Func<MyClass, string>(HelperClass.Instance.LambdaByName)));
}
void LocalFunction(IEnumerable<MyClass> myItems)
{
var lk = myItems.ToLookup(
new Func<MyClass, string>(HelperClass.Instance.LocalFunctionByName)));
}
注意Lambda
如何仅分配委托一次并在之后使用缓存委托,而LocalFunction
每次都分配委托。这使Lambda
在这种特定情况下更有效率。
虽然有a proposal on GitHub to change the compiler to make LocalFunction
as efficient as Lambda
。