Компилятор сгенерировал неверный код для анонимных методов [MS BUG FIXED]

См. Следующий код:

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(); выдает исключение. Внутри сгенерированного CIL метода Bang я получил:

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>. Это ошибка? Кстати, без использования delegate{ } (лямбда-выражение такое же), код отлично работает с синтаксическими сахарами.

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

ИЗМЕНИТЬ Я использую VS2012 RTMRel в Windows8 RTM, .NET framework 4.5

РЕДАКТИРОВАТЬ Теперь эта ошибка исправлена.


person Cheng Chen    schedule 10.10.2012    source источник
comment
Ваш код у меня работает. Какую версию C # /. Net / Visual Studio вы используете? На какую платформу вы ориентируетесь?   -  person jeroenh    schedule 10.10.2012
comment
@jeroenh: C # 4.5 VS2012.   -  person Cheng Chen    schedule 10.10.2012
comment
Я пробовал с VS2010, C # 4 и 3.5. У меня нет доступа к 2012 году прямо сейчас, но я обязательно попробую его сегодня вечером.   -  person jeroenh    schedule 10.10.2012
comment
Подтверждено на VS2012. Получает "аргумент типа" T "нарушает ограничение параметра типа" T ". что интересно.   -  person leppie    schedule 10.10.2012
comment
Выходные данные PEVerify показывают, что в компиляторе действительно есть ошибка ... [IL]: Error: [ConsoleApplication3.exe : ConsoleApplication3.Derived::<>n__FabricatedMethod1[T]][ offset 0x00000001] Unable to resolve token. 1 Error(s) Verifying ConsoleApplication3.exe   -  person leppie    schedule 10.10.2012
comment
@leppie: LOL Я делаю то же самое.   -  person Cheng Chen    schedule 10.10.2012
comment
Я думаю, что, основываясь на комментариях, вы можете с уверенностью сказать, что нашли ошибку, и ответить этим на свой вопрос. Единственный способ, которым это может быть что-то иное, кроме ошибки компилятора, - это если спецификация языка не разрешает base вызов метода в делегатах (я не проверял), но даже в этом случае отсутствие правильной диагностики является отсутствующим желаемым функция в компиляторе. (Конечно, сообщите об этом в Microsoft.)   -  person    schedule 10.10.2012
comment
Кстати, если вы удалите ограничение where T : class из виртуального метода. Код проверяется и работает правильно.   -  person leppie    schedule 10.10.2012
comment
where T : struct тоже не работает, но where T : IComparable или where T : Base работает. Изменить: where T : new() тоже не работает.   -  person leppie    schedule 10.10.2012
comment
@leppie: Сообщено в MS, номер билета: 766845   -  person Cheng Chen    schedule 10.10.2012
comment
@DannyChen: :) Я добавил сюда ссылку для справки.   -  person leppie    schedule 10.10.2012
comment
Это похоже на stackoverflow.com/questions/5290559/, хотя это вызвало BadImageFormatException, и MS утверждает, что это было исправлено.   -  person svick    schedule 10.10.2012
comment
Мне это кажется странным. Разве там нет делегата, независимо от того, используете ли вы ключевое слово делегата явно или нет? Я думал, что эти два синтаксиса эквивалентны, и поэтому удивлен, что они могут привести к разному IL, если только фактический синтаксический анализ не содержит ошибки с более далеко идущими последствиями.   -  person The Dag    schedule 11.10.2012
comment
@TheDag Разве синтаксис делегата {} не создает дополнительный анонимный метод, который затем вызывает Foo, тогда как новое действие (base.Foo ‹string›) вызывает Foo напрямую, без лишнего косвенного обращения?   -  person BrandonAGr    schedule 15.10.2012
comment
Почему вы чувствуете необходимость облепить ссылку и фиксированный статус по всему вопросу?   -  person BoltClock    schedule 14.12.2012


Ответы (2)


Это подтверждено как ошибка и теперь исправлено

Обновление: статьи о подключении больше не существует. Ошибка исправлена.

person Cheng Chen    schedule 14.12.2012
comment
Жаль, что мы никогда не узнаем, когда это дойдет до нас. Microsoft действительно должна лучше общаться на этом сайте ... - person leppie; 14.12.2012

Сначала - это возможный способ исправить это, но, вероятно, это не ответ на ваш вопрос. (Но в комментариях отсутствует форматирование кода)

Я считаю, что это похоже на следующее: Ловушка внешней переменной, потому что вы используете метод Foo () в качестве переменная и есть ошибка (или, возможно, функция) в .NET

Я попытался изменить метод Bang () на этот

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

И это работает, и результат "базовый"

Надеюсь, это немного поможет.

person Ondra    schedule 17.10.2012
comment
К вашему сведению, комментарии имеют форматирование кода, вы просто не можете включать разрывы строк и по-прежнему ограничены общим количеством символов (включая разметку) - person Adam Robinson; 25.10.2012