如果可用,使用C#方法组有什么好处吗?

Chr*_*sal 19 c# method-group

处理类似的事情时,List<string>您可以写下以下内容:

list.ForEach(x => Console.WriteLine(x));
Run Code Online (Sandbox Code Playgroud)

或者您可以使用方法组执行相同的操作:

list.ForEach(Console.WriteLine);
Run Code Online (Sandbox Code Playgroud)

我更喜欢第二行代码,因为它对我来说看起来更干净,但这有什么好处吗?

Bri*_*eon 23

好吧,让我们来看看会发生什么.

static void MethodGroup()
{
    new List<string>().ForEach(Console.WriteLine);
}

static void LambdaExpression()
{
    new List<string>().ForEach(x => Console.WriteLine(x));
}
Run Code Online (Sandbox Code Playgroud)

这将编译成以下IL.

.method private hidebysig static void MethodGroup() cil managed
{
    .maxstack 8
    L_0000: newobj instance void [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
    L_0005: ldnull 
    L_0006: ldftn void [mscorlib]System.Console::WriteLine(string)
    L_000c: newobj instance void [mscorlib]System.Action`1<string>::.ctor(object, native int)
    L_0011: call instance void [mscorlib]System.Collections.Generic.List`1<string>::ForEach(class [mscorlib]System.Action`1<!0>)
    L_0016: ret 
}

.method private hidebysig static void LambdaExpression() cil managed
{
    .maxstack 8
    L_0000: newobj instance void [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
    L_0005: ldsfld class [mscorlib]System.Action`1<string> Sandbox.Program::CS$<>9__CachedAnonymousMethodDelegate1
    L_000a: brtrue.s L_001d
    L_000c: ldnull 
    L_000d: ldftn void Sandbox.Program::<LambdaExpression>b__0(string)
    L_0013: newobj instance void [mscorlib]System.Action`1<string>::.ctor(object, native int)
    L_0018: stsfld class [mscorlib]System.Action`1<string> Sandbox.Program::CS$<>9__CachedAnonymousMethodDelegate1
    L_001d: ldsfld class [mscorlib]System.Action`1<string> Sandbox.Program::CS$<>9__CachedAnonymousMethodDelegate1
    L_0022: call instance void [mscorlib]System.Collections.Generic.List`1<string>::ForEach(class [mscorlib]System.Action`1<!0>)
    L_0027: ret 
}
Run Code Online (Sandbox Code Playgroud)

注意方法组方法如何Action<T>为一次性使用创建委托,lambda表达式方法创建隐藏的匿名委托字段,并在必要时对其进行内联初始化.通知brtrue说明IL_000a.

  • @MH你可以使用LINQPad查看编译后的IL (2认同)

Mik*_*keP 9

使用lambda表达式时,有一个额外的间接级别.使用像这样的非闭包表达式,您只需在其他方法中间进行额外的方法调用.

但是有一些有趣的差异.在第二种情况下,每次调用都会创建一个新的委托实例.对于前者,委托创建一次并缓存为隐藏字段,因此如果您要调用很多,则可以节省分配.

另外,如果将局部变量引入lambda表达式,它将成为闭包,而不仅仅是生成本地方法,将创建一个新类来保存此信息,这意味着在那里进行额外分配.


Eri*_*ert 9

正如其他人所指出的那样,lambda引起了额外的不必要的间接层.但是,语言也存在细微差别.例如,在C#3泛型类型推断的工作方式不同的M(F)比对M(x=>F(x))试图执行的返回类型推断的时候.

详情见:

http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-in​​ference-does-not-work-on-member-groups.aspx

和后续行动:

http://blogs.msdn.com/b/ericlippert/archive/2008/05/28/method-type-in​​ference-changes-part-zero.aspx


Iva*_*rić 7

我相信有一个好处.在第一种情况下,您正在创建调用Console.Writeline(string)函数的匿名方法,而在另一种情况下,您只是将引用传递给现有函数.

  • 是的,这也是我的感受.我想,优化器可能会认识到这一点并删除额外的,不必要的调用,但是当它实际上更容易编写"更好"的方式时,这样做是有意义的,IMO.我写了一篇关于这个主题的博客文章(不必使用像这样的Lambda表达式:http://www.andrewbarber.com/post/When-to-Avoid-Lambda-Expressions-or-What-Anonymous-Methods.aspx) (3认同)