动作委托:新动作或投射动作

本文关键字:新动作 | 更新日期: 2023-09-27 18:11:48

我发现了两种不同的方法来初始化一个带有Action的Delegate:

创建一个新的动作或转换为action。

Delegate foo = new Action(() => DoNothing(param));
Delegate bar = (Action)(() => DoNothing(param));

这两种语法有区别吗?

哪个更好,为什么?

在本例中使用

Delegate是因为该语法对于使用lambda表达式调用BeginInvoke或Invoke等方法很有用,并且将lambda表达式强制转换为操作

很重要。
static main 
{
    Invoke((Action)(() => DoNothing())); // OK
    Invoke(new Action(() => DoNothing())); // OK
    Invoke(() => DoNothing()); // Doesn't compil
}
private static void Invoke(Delegate del) { }
但是有趣的是编译器授权了:
Action action = () => DoNothing();
Invoke(action);

动作委托:新动作或投射动作

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

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

控制台程序:

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

代码:

// 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

我认为没有区别。

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

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

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

这是有效的,因为像这样的lambda方法不返回任何值,也不接受任何参数,因此编译器可以根据它经过委托系统来验证它是否"可映射"到一个Action。

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

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

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

大致相当于:

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

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

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

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

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

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

Delegate bar = (Action)(() => DoNothing(param));  // (from your question)