Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Action to Delegate : new Action or casting Action?

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);
like image 274
Hyralex Avatar asked May 02 '13 00:05

Hyralex


People also ask

What is delegate 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.

What is action t used for in an application?

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.

What is action in Linq?

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.

How do you use delegates?

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.


2 Answers

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
like image 121
Hyralex Avatar answered Oct 18 '22 15:10

Hyralex


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.

like image 29
Clint Avatar answered Oct 18 '22 16:10

Clint