Action to Delegate : new Action or casting Action?
Solution 1
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
Solution 2
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.
Comments
-
Hyralex almost 2 years
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);
-
Hyralex almost 11 yearsI did some test and there is no difference. After disassembly, the IL and machine code are the same.
-
Hyralex almost 11 yearsSome methods like Invoke or BeginInvoke need a Delegate, and it's necessary to cast or create an Action to use lambda expression.
-
Jeppe Stig Nielsen almost 11 years@Hyralex But all concrete delegate types, including
System.Action
, derive (viaSystem.MulticastDelegate
) fromSystem.Delegate
. Therefore the methodsInvoke
andBeginInvoke
and other members are inherited. So you could say e.g.Action bar = () => DoNothing(param); bar.BeginInvoke( ... );
. So I don't understand. -
Hyralex almost 11 yearsI'm talking about BeginInvoke and Invoke of existing object like Dispatcher. I edited my question to put more example.
-
Jeppe Stig Nielsen almost 11 yearsIt's not particularly interesting, they are just two syntaxes that lead to the same IL. So this has no relation to performance, so what do you want him to share? Read the C# Language Specification if you want details. The first expression is in 7.6.10.5 Delegate creation expressions, and the second one is in 6.5 Anonymous function conversions. Section numbers are from version 5.0 of the document. Note that 7.6.10.5 clearly says that it is processed the same way as in 6.5.
-
Jeppe Stig Nielsen almost 11 years(This comment replaces previous comment.) I was wrong about
Invoke
andBeginInvoke
. They don't exist onSystem.Delegate
since the signature is not known at that "level". So they are not inherited, they are declared on the concrete typeSystem.Action
(and any other concrete delegate type). The methodDynamicInvoke
, on the other hand, is an example of an inherited method.