When dealing with something like a List<string>
you can write the following:
list.ForEach(x => Console.WriteLine(x));
or you can use a method group to do the same operation:
list.ForEach(Console.WriteLine);
I prefer the second line of code because it looks cleaner to me, but are there any benefits to this?
Your AC will actually run longer overall if it is left on all day instead of being shut off. If you turn it off for part of the day, it runs less and results in more energy savings for you. In almost all cases, it will save you money to shut off your AC while you are away from home.
Well, let's 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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With