Ошибка компилятора при использовании?. приводя к плохому изображению, которое не сработает PEVerify

Я наткнулся на что-то странное: я получил BadImageFormatException, не зная, какое изображение (сборка) он мог бы назвать.

Я уменьшил решение, чтобы он состоял только из одного проекта без зависимостей:

введите описание изображения здесь

Как вы можете видеть, он использует только Systemmscorlib), и, конечно же, я не загружаю сборки во время выполнения.

Он компилируется как AnyCpu с .NET 4.5.2, VS 2015 с С# 6, хотя ничто из этого не имеет значения.

Я попытался сделать образец с С# 5, но как только я заменил все "?". операторов, это прекращается.

Я организовал проект, чтобы люди могли сами попробовать:

git clone -b crash-sample https://github.com/jtheisen/moldinium.git

Я очистил и протестировал его на 4 машинах, все они показали тот же эффект.

Трассировка стека аварии:

Ex.: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
   at IronStone.Moldinium.LiveList.<>c__DisplayClass10_0`1.<Where>b__2(ListEvent`1 v)
   at IronStone.Moldinium.ActionObserver`1.OnNext(T value) in C:\Source\Repos\moldinium\ConsoleApplication1\Rx.cs:line 51
...snipped...

Запуск PEVerify на выходе вызывает следующую ошибку:

[IL]: Ошибка: [C:\Source\Repos\moldinium\ConsoleApplication1\bin\Debug\Bad.exe: IronStone.Moldinium.LiveList + < > c__DisplayClass10_0`1 [TSource]:: b__2] [смещение 0x0000013B] Невозможно разрешить токен.

Удаление всех операторов ?. из файла Select.cs устраняет проблему.

Используя ILSpy, я выделил проблему:

IronStone.Moldinium.LiveList.<>c__DisplayClass10_0`1.<Where>b__2

Вы можете увидеть IL Dumps метода (через ILSpy) в gist здесь. Bad IL при использовании ?. Good IL - это стиль С# 5.0.

Это было построено с помощью VS2015.3

Версия CSC: Microsoft (R) Visual С# Компилятор версии 1.3.1.60616

Ответы

Ответ 1

Я не могу вам помочь, потому что это действительно ошибка. Но я могу довести вас до точки, где происходит ошибка, и это может помочь вам воспроизвести ошибку в нескольких строках кода.

namespace ElvisBugInNullableGenericStructWithNestedTypeParameter
{
    struct MyGenericStruct<T> { }
    class Program
    {
        static void Main() { }

        void Test<T>()
        {
            Func<T, bool> func = (arg =>
                {
                    MyGenericStruct<T>? v1 = null;
                    return v1?.ToString() == null;
                });
        }
    }
}

Если я заменил MyGenericStruct<T>? на MyGenericStruct<int>?, он будет работать.

Проблема заключается в том, что по какой-то причине, когда мы используем внешнюю T в nullable struct, а затем мы пытаемся использовать оператор Elvis ?, тип неизвестен (не удается разрешить токен).

Обновление Если вы хотите исправить свое дело, вам не нужно удалять весь оператор Элвиса, просто удалите их из действия Subscribe в рамках метода public static ILiveList<TSource> Where<TSource>(this ILiveList<TSource> source, Func<TSource, Boolean> predicate).