C#编译器与古怪建设者代表 [英] C# compiler oddity with delegate constructors

查看:93
本文介绍了C#编译器与古怪建设者代表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基于以下问题的

,我发现C#编译器的一些奇怪的行为。



以下是有效的C#:

 静态无效K(){} 

上配置静态无效的主要()
{
变种K =新的行动(新的Action(动作新(K))));
}



我不觉得奇怪的是编译器'解构'所传递的委托。



ILSpy输出如下:

 新的Action(新动作(新动作(NULL,ldftn(K)),ldftn(调用))调用)。 



正如人们所看到的,它会自动决定使用调用委托的方法。但是,为什么?



正因为如此,该代码还不清楚。我们有一个三重包裹的代表(实际),或者仅仅是复制到外的人(我最初的想法)内委托。



当然,如果意图是象发出的代码编译器,应该写:

  VAR K =新的Action(新动作(新动作(K) .Invoke).Invoke); 

要反编译代码类似。



?谁能证明这个奇怪转变的原因。



更新:



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

 委托无效巴兹(); 
委托无效酒吧();
...
变种K =新巴兹(新酒吧(新动作(K)));



也许编译器应该发出一个警告,如果使用相同的委托类型。


解决方案

该规范(第7.6.10.5)说:





  • 新的委托实例初始化具有相同的调用列表,通过电子邮件给委托实例。




现在假设编译器将其转换为类似于您的建议的内容:

 新的行动(a .TARGET,a.Method)

这将永远只能创建委托具有的调用列表的方法调用。对于多播委托,就违反了规范



示例代码:

 使用系统; 

类节目
{
静态无效的主要(字串[] args)
{
先行动=()=> Console.WriteLine(第一);
行动秒=()=> Console.WriteLine(二);

两种行动第一= +第二;
行动wrapped1 =
(行动)Delegate.CreateDelegate(typeof运算(动作),
both.Target,both.Method);
行动wrapped2 =新的行动(两者);

Console.WriteLine(调用wrapped1:);
wrapped1();

Console.WriteLine(调用wrapped2:);
wrapped2();
}
}



输出:


$
第二
调用wrapped2:
首先
第二
 电话wrapped1 > 

正如你所看到的,的真正的编译器的行为规范相匹配 - 你的建议的行为并不

这是部分原因是有些奇怪,有时单投,有时多播代表,的性质当然...


Based on the following question, I found some odd behaviour of the c# compiler.

The following is valid 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.

The ILSpy output is as follows:

new Action(new Action(new Action(null, ldftn(K)), ldftn(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);

Similar to the decompiled code.

Can anyone justify the reason for this 'surprising' transformation?

Update:

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.

解决方案

The spec (section 7.6.10.5) says:

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

Now suppose the compiler translated it to something similar to your suggestion of:

new Action( a.Target, a.Method)

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.

Sample code:

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();
    }
}

Output:

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.

This is partly due to the somewhat odd "sometimes single-cast, sometimes multi-cast" nature of Delegate, of course...

这篇关于C#编译器与古怪建设者代表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆