问题描述
根据以下问题,我发现了 c# 编译器的一些奇怪行为.
Based on the following question, I found some odd behaviour of the c# compiler.
以下是有效的 C#:
static void K() {}
static void Main()
{
var k = new Action(new Action(new Action(K))));
}
我觉得奇怪的是编译器解构"传递的委托.
What I do find strange is the compiler 'deconstructing' the passed delegate.
ILSpy 输出如下:
The ILSpy output is as follows:
new Action(new Action(new Action(null, ldftn(K)), ldftn(Invoke)).Invoke);
可以看到,它自动决定使用委托的Invoke
方法.但为什么呢?
As one can see, it automatically decides to use the Invoke
method of the delegate. But why?
事实上,代码不清楚.我们有一个三重包装的委托(实际)还是内部委托只是复制"到外部委托(我最初的想法).
As it is, the code is unclear. Do we have a triply-wrapped delegate (actual) or is the inner delegate just 'copied' to the outer ones (my initial thought).
当然,如果意图就像编译器发出代码一样,应该这样写:
Surely if the intent was like the compiler emitted the code, one should have written:
var k = new Action(new Action(new Action(K).Invoke).Invoke);
类似于反编译的代码.
谁能证明这种令人惊讶"转变的原因?
Can anyone justify the reason for this 'surprising' transformation?
更新:
我只能想到一个可能的用例;委托类型转换.例如:
I can only think of one possible use-case for this; delegate type conversion. Eg:
delegate void Baz();
delegate void Bar();
...
var k = new Baz(new Bar( new Action (K)));
如果使用相同的委托类型,编译器可能会发出警告.
Perhaps the compiler should emit a warning if the same delegate types are used.
推荐答案
规范(第 7.6.10.5 节)说:
The spec (section 7.6.10.5) says:
- 新的委托实例使用与 E 给出的委托实例相同的调用列表进行初始化.
现在假设编译器将其翻译成类似于您的建议的内容:
Now suppose the compiler translated it to something similar to your suggestion of:
new Action( a.Target, a.Method)
这只会创建一个带有 single 方法调用的调用列表的委托.对于多播委托,这将违反规范.
That would only ever create a delegate with an invocation list of a single method call. For a multi-cast delegate, it would violate the spec.
示例代码:
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();
}
}
输出:
Calling wrapped1:
Second
Calling wrapped2:
First
Second
如您所见,编译器的 真实 行为符合规范 - 您建议的行为不符合.
As you can see, the real behaviour of the compiler matches the spec - your suggested behaviour doesn't.
这部分是由于 Delegate
有点奇怪的有时是单播,有时是多播"的性质,当然...
This is partly due to the somewhat odd "sometimes single-cast, sometimes multi-cast" nature of Delegate
, of course...
这篇关于带有委托构造函数的 C# 编译器异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!