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)