lep*_*pie 9 c# compiler-construction constructor delegates
基于以下问题,我发现了c#编译器的一些奇怪行为.
以下是有效的C#:
static void K() {}
static void Main()
{
var k = new Action(new Action(new Action(K))));
}
Run Code Online (Sandbox Code Playgroud)
我发现奇怪的是编译器'解构'传递的委托.
ILSpy输出如下:
new Action(new Action(new Action(null, ldftn(K)), ldftn(Invoke)).Invoke);
Run Code Online (Sandbox Code Playgroud)
可以看出,它会自动决定使用Invoke委托的方法.但为什么?
实际上,代码不清楚.我们是否有一个三重包装的委托(实际)或内部委托只是'复制'到外部委托(我最初的想法).
当然,如果意图就像编译器发出代码一样,那么应该写一下:
var k = new Action(new Action(new Action(K).Invoke).Invoke);
Run Code Online (Sandbox Code Playgroud)
与反编译代码类似.
任何人都可以证明这种"令人惊讶的"转变的原因吗?
更新:
我只能想到一个可能的用例; 委托类型转换.例如:
delegate void Baz();
delegate void Bar();
...
var k = new Baz(new Bar( new Action (K)));
Run Code Online (Sandbox Code Playgroud)
如果使用相同的委托类型,编译器可能会发出警告.
规范(第7.6.10.5节)说:
- 使用与E给出的委托实例相同的调用列表初始化新的委托实例.
现在假设编译器将其翻译成类似于您的建议:
new Action( a.Target, a.Method)
Run Code Online (Sandbox Code Playgroud)
这只会创建一个具有单个方法调用的调用列表的委托.对于多播代表,它会违反规范.
示例代码:
using System;
class Program
{
static void Main(string[] args)
{
Action first = () => Console.WriteLine("First");
Action second = () => Console.WriteLine("Second");
Action both = first + second;
Action wrapped1 =
(Action) Delegate.CreateDelegate(typeof(Action),
both.Target, both.Method);
Action wrapped2 = new Action(both);
Console.WriteLine("Calling wrapped1:");
wrapped1();
Console.WriteLine("Calling wrapped2:");
wrapped2();
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Calling wrapped1:
Second
Calling wrapped2:
First
Second
Run Code Online (Sandbox Code Playgroud)
如您所见,编译器的实际行为与规范相匹配 - 您建议的行为不符合规范.
部分原因在于有些奇怪的"有时是单演,有时是多演员"的性质Delegate,当然......