Are there any benefits to using a C# method group if available?

前端 未结 7 1084
孤街浪徒
孤街浪徒 2020-12-03 10:55

When dealing with something like a List you can write the following:

list.ForEach(x => Console.WriteLine(x));

相关标签:
7条回答
  • 2020-12-03 11:08

    Well, lets take a look and see what happens.

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

    This gets compiled into the following 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 
    }
    

    Notice how the method group approach creates an Action<T> delegate for one time use and the lambda expression approach creates a hidden anonymous delegate field and does an inline initialization of it if necessary. Notice brtrue instruction at IL_000a.

    0 讨论(0)
  • 2020-12-03 11:13

    I believe that there is a benefit. In first case you are creating anonymous method which calls Console.Writeline(string) function while in the other case you are just passing the reference to existing function.

    0 讨论(0)
  • 2020-12-03 11:26

    Personally I also prefer the second because it's less confusing to debug, but in this case I think it's just a matter of style since they both end up getting the same thing done.

    0 讨论(0)
  • 2020-12-03 11:29

    As others have noted, there is an extra unnecessary layer of indirection induced by the lambda. However, there are subtle language differences as well. For example, in C# 3 generic type inference works differently on M(F) than on M(x=>F(x)) when attempting to perform return type inference.

    For details see:

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

    and the follow-up:

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

    0 讨论(0)
  • 2020-12-03 11:31

    There is an extra level of indirection when using the lambda expression. With a non-closure expression like that, you'll simply have an extra method call in-between, as mentioned by others.

    There are a few interesting differences though. In the second case, a new delegate instance is being created on each call. For the former, the delegate is created once and cached as a hidden field, so if you're calling a lot you'll save on allocations.

    Additionally, if you introduce a local variable into the lambda expression, it becomes a closure and instead of just a local method being generated, a new class will be created to hold this information, meaning an extra allocation there.

    0 讨论(0)
  • 2020-12-03 11:31

    Yes; the first actually can cause an unnecessary extra, interim call to happen; passing x in to a method that simply calls Console.WriteLine(x); You don't need to do the first one because Console.WriteLine already is a method which matches the signature that ForEach is looking for.

    0 讨论(0)
提交回复
热议问题