I found two different ways to initialize a Delegate with an Action :
Create a new action or casting to Action.
Delegate foo = new Action(() => DoNothing(param));
Delegate bar = (Action)(() => DoNothing(param));
Is there a difference between this 2 syntaxes?
Which one is better and why?
Delegate is use in this example because the syntaxes is useful to call methods like BeginInvoke or Invoke with a lambda expression, and it's important to cast the lambda expression into an action
static main
{
Invoke((Action)(() => DoNothing())); // OK
Invoke(new Action(() => DoNothing())); // OK
Invoke(() => DoNothing()); // Doesn't compil
}
private static void Invoke(Delegate del) { }
But it's interesting to see that the compiler authorized this :
Action action = () => DoNothing();
Invoke(action);
Action is a delegate type defined in the System namespace. An Action type delegate is the same as Func delegate except that the Action delegate doesn't return a value. In other words, an Action delegate can be used with a method that has a void return type. For example, the following delegate prints an int value.
You can use the Action<T> delegate to pass a method as a parameter without explicitly declaring a custom delegate. The encapsulated method must correspond to the method signature that is defined by this delegate.
LINQ in Action is a fast-paced, comprehensive tutorial for professional developers who want to use LINQ. This book explores what can be done with LINQ, shows you how it works in an application, and addresses the emerging best practices.
Delegates allow methods to be passed as parameters. Delegates can be used to define callback methods. Delegates can be chained together; for example, multiple methods can be called on a single event. Methods don't have to match the delegate type exactly.
There is no difference between this two instruction. In the both instruction, a new instance of Action is created.
The IL code below seems to confirm this.
Console Program :
class Program
{
static void Main(string[] args)
{
Delegate barInit = (Action)(() => DoNothing());
Delegate fooInit = new Action(() => DoNothing());
}
private static void DoNothing() { }
}
IL Code :
// First instruction
IL_0000: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2'
IL_0005: brtrue.s IL_0018
IL_0007: ldnull
IL_0008: ldftn void CodeMachineTest.Program::'<Main>b__0'()
// Create a new Action instance for the instruction (Action)(() => DoNothing())
IL_000e: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
IL_0013: stsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2'
IL_0018: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2'
IL_001d: pop
// Second instruction
IL_001e: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_0023: brtrue.s IL_0036
IL_0025: ldnull
IL_0026: ldftn void CodeMachineTest.Program::'<Main>b__1'()
IL_002c: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
IL_0031: stsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_0036: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_003b: pop
IL_003c: ret
To my mind there is no difference.
new Action(() => DoNothing(param));
This just creates a new Action and passes along a Lambda expression, which the compiler will deal with and see to it that everything is wired up just fine.
(Action)(() => DoNothing(param));
This works because a lambda method such as this returns no value and takes no parameters, as such the compiler can verify that it is "mappable" to an Action on the grounds that it goes through the delegate system.
They are more-or-less one and the same, depending on any sort of compiler optimisations it's hard to say which is more performant, perhaps you should test the performance and see for yourself?
It's an interesting question and an exploration into the delegation system and how Linq and Expressions fit in.
new Func<string>(() => "Boo!");
is more-or-less equivalent to:
(Func<String>)() => "Boo!";
As far as I'm aware they both end up going down through the delegate system think Invoke()
etc, it would be interesting if you did test the performance and shared your results.
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