C# 编译器与委托(delegate)构造函数的奇怪之处

标签 c# compiler-construction delegates constructor

基于following question ,我发现了 c# 编译器的一些奇怪行为。

以下是有效的 C#:

static void K() {}

static void Main()
{
  var k = new Action(new Action(new Action(K))));
}

我确实觉得奇怪的是编译器“解构”了传递的委托(delegate)。

ILSpy输出如下:

new Action(new Action(new Action(null, ldftn(K)), ldftn(Invoke)).Invoke);

如您所见,它自动决定使用委托(delegate)的 Invoke 方法。但是为什么?

事实上,代码不清楚。我们有一个三重包裹的委托(delegate)(实际)还是内部委托(delegate)只是“复制”到外部委托(delegate)(我最初的想法)。

当然,如果意图就像编译器发出的代码,那么应该这样写:

var k = new Action(new Action(new Action(K).Invoke).Invoke);

类似于反编译后的代码。

谁能证明这种“令人惊讶”转变的原因?

更新:

我只能想到一个可能的用例;委托(delegate)类型转换。例如:

delegate void Baz();
delegate void Bar();
...
var k = new Baz(new Bar( new Action (K)));

如果使用相同的委托(delegate)类型,编译器或许应该发出警告。

最佳答案

规范(第 7.6.10.5 节)说:

  • The new delegate instance is initialized with the same invocation list as the delegate instance given by E.

现在假设编译器将其翻译成类似于您建议的内容:

new Action( a.Target, a.Method)

那只会创建一个具有单个 方法调用的调用列表的委托(delegate)。对于多播委托(delegate),它会违反规范。

示例代码:

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

如您所见,编译器的真实行为符合规范 - 您建议的行为不符合。

这部分是由于 Delegate 有点奇怪的“有时是单播,有时是多播”的性质,当然...

关于C# 编译器与委托(delegate)构造函数的奇怪之处,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8077719/

相关文章:

c# - IQueryable.Where() 到底发生了什么?

ios - 委托(delegate)方法声明中的枚举

c# - 为什么任务列表中只有随机的几个任务运行完成?

c# - System.Numerics 的矩阵乘法值完全错误

c - 从函数实现返回结构

c++ - 使用 erlang 构建 C++ 编译器

ios - 通过导航 Controller 时丢失指向委托(delegate)的指针

C# 使用 WHERE 获取每个第 n 个元素,结果很奇怪

c# linq 连接具有不同名称的多个属性

compiler-construction - 是否有任何语言既没有解释器也没有编译器?