C#编译器奇怪与委托构造函数

基于以下问题 ,我发现了c#编译器的一些奇怪行为。

以下是有效的C#:

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

我发现奇怪的是编译器’解构’传递的委托。

ILSpy输出如下:

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

可以看出,它会自动决定使用委托的Invoke方法。 但为什么?

实际上,代码不清楚。 我们是否有一个三重包装的委托(实际)或内部委托只是’复制’到外部委托(我最初的想法)。

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

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

与反编译代码类似。

任何人都可以certificate这种“令人惊讶的”转变的原因吗?

更新:

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

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

如果使用相同的委托类型,编译器可能会发出警告。

规范(第7.6.10.5节)说:

  • 使用与E给出的委托实例相同的调用列表初始化新的委托实例。

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

 new Action( a.Target, a.Method) 

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

示例代码:

 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有点奇怪的“有时单演,有时多演员”的性质,当然……

当您尝试将委托视为方法时,编译器实际上使用委托的Invoke()方法。 因此,例如,下面的两行编译为完全相同的IL(都调用Invoke() ):

 k(); k.Invoke(); 

我认为你所看到的奇怪之处就是这样的结果。 委托构造函数需要一个方法(或者更确切地说,一个方法组),但它会获得一个委托。 因此它将其视为一种方法并使用Invoke()方法。

至于含义,它是调用委托调用实际方法的委托。 您可以通过访问委托的MethodTarget属性来自行validation。 在最外层委托的情况下, MethodAction.InvokeTarget内部委托。

  • 代表是一个class级
  • Action委托有一个像这样的构造函数

    public extern Action(对象@object,IntPtr方法);

  • 由于K是静态方法,因此不需要将对象作为第一个参数传递给最内部的动作实例,因此它传递null

  • 由于第二个参数是指向函数的指针,因此它使用ldftn函数传递K方法的指针
  • 对于剩余的Action实例,传递的对象是内部Action,第二个参数是Invoke方法, 因为当你调用一个委托时,你实际上是在调用Invoke方法

摘要

 var action = new Action(K) => Action action = new Action(null, ldftn(K)) new Action(action) => new Action(action, ldftn(Action.Invoke)) 

我希望这可以解释发生了什么?