C# 要委派的动作:新动作还是铸造动作?

C# 要委派的动作:新动作还是铸造动作?,c#,casting,delegates,lambda,action,C#,Casting,Delegates,Lambda,Action,我发现了两种不同的方法来初始化带有操作的委托: 创建新动作或根据动作进行强制转换 Delegate foo = new Action(() => DoNothing(param)); Delegate bar = (Action)(() => DoNothing(param)); 这两种语法之间有区别吗 哪一个更好,为什么 在本例中使用委托是因为语法对于调用BeginInvoke或使用lambda表达式调用之类的方法很有用,而且将lambda表达式强制转换为操作也很重要 stati

我发现了两种不同的方法来初始化带有操作的委托:

创建新动作或根据动作进行强制转换

Delegate foo = new Action(() => DoNothing(param));
Delegate bar = (Action)(() => DoNothing(param));
这两种语法之间有区别吗

哪一个更好,为什么

在本例中使用委托是因为语法对于调用BeginInvoke或使用lambda表达式调用之类的方法很有用,而且将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);

在我看来没有区别

new Action(() => DoNothing(param));
这只是创建了一个新的操作并传递了一个Lambda表达式,编译器将处理该表达式,并确保一切正常

(Action)(() => DoNothing(param));
这是因为像This这样的lambda方法不返回任何值,也不接受任何参数,因此编译器可以通过委托系统验证它是否“可映射”到某个操作

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

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

new Func<string>(() => "Boo!");
newfunc(()=>“Boo!”);
大致相当于:

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

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

这两条指令之间没有区别。在这两条指令中,将创建一个新的操作实例

下面的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
//第一条指令
IL_0000:ldsfld类[mscorlib]System.Action CodeMachineTest.Program:'CS$9_CachedAnonymousMethodDelegate2'
IL_0005:brtrue.s IL_0018
IL_0007:ldnull
IL_0008:ldftn无效代码机器测试程序::'b_0'()
//为指令(操作)(()=>DoNothing()创建新操作实例
IL_000e:newobj实例void[mscorlib]System.Action::.ctor(对象,本机int)
IL_0013:stsfld类[mscorlib]System.Action CodeMachineTest.Program:'CS$9_CachedAnonymousMethodDelegate2'
IL_0018:ldsfld类[mscorlib]System.Action CodeMachineTest.Program:'CS$9_CachedAnonymousMethodDelegate2'
IL_001d:流行音乐
//第二指令
IL_001e:ldsfld类[mscorlib]System.Action CodeMachineTest.Program:'CS$9_CachedAnonymousMethodDelegate3'
IL_0023:brtrue.s IL_0036
IL_0025:ldnull
IL_0026:ldftn无效代码机器测试程序::'b__1'()
IL_002c:newobj实例无效[mscorlib]系统。操作::.ctor(对象,本机int)
IL_0031:stsfld类[mscorlib]System.Action CodeMachineTest.Program:'CS$9_CachedAnonymousMethodDelegate3'
IL_0036:ldsfld类[mscorlib]System.Action CodeMachineTest.Program:'CS$9_CachedAnonymousMethodDelegate3'
IL_003b:流行音乐
IL_003c:ret

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

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

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

而不是

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

我做了一些测试,没有区别。在反汇编之后,IL和机器代码是相同的。这并不特别有趣,它们只是导致相同IL的两个语法。这和表现无关,你想让他分享什么?如果需要详细信息,请阅读C语言规范。第一个表达式在7.6.10.5委托创建表达式中,第二个表达式在6.5匿名函数转换中。章节编号来自本文件5.0版。请注意,7.6.10.5明确指出,它的处理方式与6.5中的处理方式相同。一些方法(如Invoke或BeginInvoke)需要委托,并且有必要强制转换或创建一个操作以使用lambda表达式。@Hyralex但所有具体委托类型,包括
System.Action
,都派生(通过
System.MulticastDelegate
)从
系统.委派
。因此,方法
Invoke
BeginInvoke
和其他成员被继承。所以你可以说,例如,
Action bar=()=>DoNothing(param);酒吧开始吸烟(…)。所以我不明白。我说的是对现有对象(如Dispatcher)的BeginInvoke和调用。我编辑了我的问题以提供更多的示例。(此评论取代了以前的评论。)我对
Invoke
BeginInvoke
的理解是错误的。它们不存在于
系统中。委托
,因为该“级别”上的签名未知。因此它们不是继承的,而是在具体类型
System.Action
(以及任何其他具体委托类型)上声明的。另一方面,方法
DynamicInvoke
是继承方法的一个示例。编辑:在
静态
方法中会有什么有意义的内容?没有什么有趣的。这个问题的目的只是为了理解这两种语法之间的区别。当我调用Dispatcher.Invoke()时,我真正的实现是在WPF应用程序中。您仍然应该记住,
操作
是一个
委托
,因为
操作
源自
委托
。因此,即使您使用一个重载来接收
委托
,您也可以给它一个
操作
。示例:
Action bar=()=>DoNothing(参数);一些调度员。开始吸烟(酒吧)(请参阅)。另外:在较新版本的框架.NET 4.5中,有一个超负荷的
Dispatcher.Invoke
执行
操作,但这只是为了方便起见,请参阅。我理解这一点。但是编译器不会隐式地将lambda表达式强制转换为委托,而是将其转换为动作(即委托)。这是另一个主题:)
Delegate bar = (Action)(() => DoNothing(param));  // (from your question)