编译器为匿名方法生成了错误的代码 [微软漏洞已修复]

30
请看下面的代码:
public abstract class Base
{
    public virtual void Foo<T>() where T : class
    {
        Console.WriteLine("base");
    }
}

public class Derived : Base
{
    public override void Foo<T>()
    {
        Console.WriteLine("derived");
    }

    public void Bang()
    {
        Action bang = new Action(delegate { base.Foo<string>(); });
        bang();    //VerificationException is thrown
    }
}

new Derived().Bang(); 抛出了一个异常。在方法 Bang 的生成的 CIL 中,我得到了以下内容:

call instance void ConsoleApp.Derived::'<>n__FabricatedMethod1'<string>()

以及编译器生成方法的签名:

method private hidebysig 
    instance void '<>n__FabricatedMethod1'<T> () cil managed 
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )       
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void ConsoleApp.Base::Foo<!!T>()
    IL_0006: ret
}

我认为正确的代码应该是'<>n__FabricatedMethod1'<class T>。这是个bug吗?顺便说一下,如果不使用delegate{}(lambda表达式也一样),代码在语法糖的情况下能够正常工作。

Action good = new Action(base.Foo<string>());
good();  //fine

编辑 我正在使用Windows8 RTM中的VS2012 RTMRel,.net框架4.5。

编辑 此错误现已修复。


1
你的代码在我这里可以运行。你使用的是哪个版本的C#/.Net/Visual Studio?你的目标平台是什么? - jeroenh
2
从PEVerify的输出可以看出,编译器确实存在一个错误... [IL]: Error: [ConsoleApplication3.exe : ConsoleApplication3.Derived::<>n__FabricatedMethod1[T]][offset 0x00000001] Unable to resolve token. 1 Error(s) Verifying ConsoleApplication3.exe - leppie
7
根据目前的评论,我认为你可以相当安全地说你已经发现了一个bug,并且可以用这个来回答自己的问题。除非语言规范不允许在委托中调用"base"方法(我没有检查),否则这种情况除了编译器bug之外别无他法。即便是这种情况,编译器缺乏适当的诊断仍然是一项缺失的理想功能。(当然要向Microsoft报告这个bug。) - user743382
7
@leppie:已向微软报告,工单号为:766845。 - Cheng Chen
1
@TheDag 委托 { } 语法是否会创建一个额外的匿名方法,然后调用 Foo,而 new Action(base.Foo<string>) 则直接调用 Foo 而没有额外的间接操作? - BrandonAGr
显示剩余10条评论
2个回答

3

已确认为一个错误并已经被修复

更新:连接的文章已不存在。该错误已经被修复。


1
遗憾的是,我们永远不会知道这将何时到达我们。微软应该在那个网站上更好地沟通... - leppie

1

首先 - 这是可能修复此问题的一种方式,但可能不是您问题的答案。(但评论没有代码格式)

我认为这与 外部变量陷阱 类似,因为您正在将 Foo() 方法用作变量,并且 .NET 中存在错误(或者可能是功能)

我已尝试将 Bang() 方法更改为以下内容

public void Bang()
{
    Action baseMethod = base.Foo<string>;
    Action bang = new Action(delegate { baseMethod(); });
    bang();    //VerificationException is thrown
}

它可以工作,结果是“基础”

希望能有所帮助。


请注意,注释确实具有代码格式,您只需不包括换行符,并且仍受总字符数的限制(其中包括Markdown)。 - Adam Robinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接