我找到了两种使用Action初始化委托的方法:
创建新动作或强制转换为动作。
Delegate foo = new Action(() => DoNothing(param));
Delegate bar = (Action)(() => DoNothing(param));
这2种语法之间有区别吗?
哪一个更好,为什么?
在这个例子中使用了委托,因为语法对于使用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);
答案 0 :(得分:12)
这两条指令没有区别。在这两个指令中,创建了一个新的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
答案 1 :(得分:2)
在我看来,没有区别。
new Action(() => DoNothing(param));
这只是创建一个新的Action并传递一个Lambda表达式,编译器将处理该表达式,并确保所有内容都已正常连接。
(Action)(() => DoNothing(param));
这是有效的,因为像这样的lambda方法不返回任何值并且不带参数,因此编译器可以验证它是否可以“映射”到Action,因为它通过委托系统。
它们或多或少是相同的,取决于任何类型的编译器优化,很难说哪个更高性能,也许你应该测试性能并亲眼看看?
这是一个有趣的问题,也是对委托系统以及Linq和表达式如何适应的探索。
new Func<string>(() => "Boo!");
或多或少等同于:
(Func<String>)() => "Boo!";
据我所知,他们最终都会通过委托系统思考Invoke()
等,如果您测试了性能并分享了结果,那将会很有趣。
答案 2 :(得分:0)
没有区别,它们只是两种语法。就个人而言,我使用最后一个,因为它更短。
但为什么需要Delegate
类型的变量?在大多数情况下,您希望变量与实例具有相同的类型,然后您可以使用
var bar = (Action)(() => DoNothing(param));
或
Action bar = () => DoNothing(param);
而不是
Delegate bar = (Action)(() => DoNothing(param)); // (from your question)