带有委托构造函数的 C# 编译器异常

C# compiler oddity with delegate constructors(带有委托构造函数的 C# 编译器异常)

本文介绍了带有委托构造函数的 C# 编译器异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据以下问题,我发现了 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# 编译器异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:带有委托构造函数的 C# 编译器异常

基础教程推荐