15

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);
4

3 回答 3

13

这两条指令没有区别。在这两个指令中,创建了一个新的 Action 实例。

下面的 IL 代码似乎证实了这一点。

控制台程序:

class Program
{
    static void Main(string[] args)
    {
        Delegate barInit = (Action)(() => DoNothing());
        Delegate fooInit = new Action(() => DoNothing());
    }

    private static void DoNothing() { }
}

IL代码:

// 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
于 2013-05-02T01:56:38.440 回答
2

在我看来没有区别。

new Action(() => DoNothing(param));

这只是创建了一个新的 Action 并传递了一个 Lambda 表达式,编译器将处理它并确保一切都正常连接。

(Action)(() => DoNothing(param));

这是有效的,因为像这样的 lambda 方法不返回值也不接受参数,因此编译器可以验证它是否“可映射”到 Action,因为它通过了委托系统。

它们或多或少是相同的,取决于任何类型的编译器优化,很难说哪个性能更高,也许您应该测试性能并自己看看?

这是一个有趣的问题,也是对委托系统以及 Linq 和 Expressions 如何适应的探索。

new Func<string>(() => "Boo!");

或多或少等同于:

(Func<String>)() => "Boo!";

据我所知,他们最终都会通过委托系统思考Invoke()等等,如果您确实测试了性能并分享了您的结果,那将会很有趣。

于 2013-05-02T00:42:18.043 回答
0

没有区别,它们只是相同的两种语法。就个人而言,我使用最后一个,因为它更短。

但是为什么你需要一个类型的变量Delegate呢?在大多数情况下,您希望变量与实例具有相同的类型,然后您可以使用

var bar = (Action)(() => DoNothing(param));

或者

Action bar = () => DoNothing(param);

代替

Delegate bar = (Action)(() => DoNothing(param));  // (from your question)
于 2013-05-02T15:37:20.640 回答