BadImageFormatException при использовании IEnumerable и множественного наследования

Сегодня у меня возникла очень странная проблема, которую я смог решить, но до сих пор не понимаю, почему это происходит. Это сценарий:

РЕДАКТИРОВАТЬ

Я изменил сценарий, чтобы сделать его намного проще: у меня есть программа, которая выполняет код, и 2 импортера, базовый класс с универсальным типом и еще один класс (ImplementingImporter), который просто вызывает базовый метод и перебирает его. Это полный код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IEnumeratorLoadProblem {
    class Program {
        static void Main(string[] args) {

            var importer = new ImplementingImporter();
            try {
                var data = importer.GetData().ToArray();
            } catch (BadImageFormatException ex) {                
                Console.WriteLine("Why does this fail? " + ex.ToString());
            }

            Console.WriteLine("Press enter to quit");
            Console.ReadLine();
        }
    }

    class BaseClassImporter<T> {

        public virtual IEnumerable<T> GetData() {
            yield break;
        }
    }

    class ImplementingImporter : BaseClassImporter<int> {
        public override IEnumerable<int> GetData() {
            // iterating seems to cause the problem
            foreach(var dataByBaseImpl in base.GetData()) {
                yield return dataByBaseImpl;
            }
        }
    }
}

Я получаю следующую ошибку:

System.BadImageFormatException: была предпринята попытка загрузить программу с неправильным форматом. (Исключение из HRESULT: 0x8007000B)

Когда я меняю код с используемого импортера на него работает:

class ImplementingImporter : BaseClassImporter<int> {
    protected override IEnumerable<int> GetData() {
        return base.GetData();
    }
}

К сожалению, я не смог просмотреть сгенерированный IL-код, потому что и ILSpy, и Reflector.NET (версия 6) отображали внутреннюю ошибку (думаю, это было исключение ArgumentOutOfRangeException). Я боялся использовать ildasm, поэтому не пытался смотреть IL Code напрямую.

Я предполагаю, что это как-то связано с сгенерированным кодом IL, но я не могу придумать сценарий, вызывающий проблему.

Любые идеи, что здесь происходит? Если сценарий недостаточно ясен, пожалуйста, оставьте комментарий, и я постараюсь сделать его более понятным.

РЕДАКТИРОВАТЬ:

Используемая версия .NET: 4.0. Приложение представляет собой консольное приложение, использующее VS 2010 SP1. Целью платформы сборки является AnyCPu, но проблема также проявляется при использовании x86. Моя машина имеет 64-битную систему (Windows 7). Исключение также возникает при использовании клиентского профиля .NET 4.0.

Пример представляет собой один проект, внешние/неуправляемые библиотеки не используются, поэтому не должны возникать только предлагаемые проблемы (например, ссылка на 32-разрядную сборку при запуске 64-разрядной версии).


person Bernhard Kircher    schedule 14.08.2012    source источник
comment
Это исключение обычно возникает, когда вы находитесь в 32/64-битном процессе и пытаетесь загрузить DLL другой разрядности. Процесс может быть нацелен только на одну платформу, и после выбора могут быть загружены только библиотеки DLL той же платформы (однажды 32-разрядная, всегда 32-разрядная — то же самое для 64-разрядной). Убедитесь, что целевая платформа в DLL, которые вы создаете, одинакова: либо x86/x64 явно (но все равно), либо AnyCPU для неявного выбора разрядности.   -  person Adam Houldsworth    schedule 14.08.2012
comment
Это тоже было мое первое предположение, поэтому я проверил параметры и создал один проект, чтобы воспроизвести проблему (думаю, это не должно быть проблемой сборки, когда все находится в одной сборке). Я собираюсь добавить в вопрос другую информацию об используемой версии .NET и т. д.   -  person Bernhard Kircher    schedule 14.08.2012
comment
Это же правило применяется к другим управляемым и неуправляемым библиотекам DLL сторонних производителей, которые также запускаются в процессе.   -  person Adam Houldsworth    schedule 14.08.2012
comment
Решение содержит только один проект и не включает внешние библиотеки DLL. Должна быть возможность скопировать данный сценарий в один файл и запустить его. Может быть, я могу упростить сценарий.   -  person Bernhard Kircher    schedule 14.08.2012
comment
Я обновил пример, чтобы воспроизвести проблему.   -  person Bernhard Kircher    schedule 14.08.2012
comment
Интересно, я предполагаю, что это как-то связано с кодом, созданным компилятором для поддержки ключевого слова yield.   -  person Adam Houldsworth    schedule 14.08.2012


Ответы (2)


Похоже, это ошибка с оператором yield return:

https://connect.microsoft.com/VisualStudio/feedback/details/677532/попытка-была-предпринята-загрузка-программы-с-исключением-неверным-форматом-от-hresult-0x8007000b#details

Они заявляют, что это исправлено в VS2012 (или «версии после VS 2010»).

Я запускаю консольное приложение для .NET Framework 4 с использованием VS2010 SP1 и могу подтвердить, что получаю ту же ошибку, что и вы. У меня нет доступной установки VS2012, чтобы попробовать это.

Подобный вопрос был задан здесь:

Блоки итератора и наследование

Еще один подозрительно похожий пример (на этот раз с асинхронностью, но снова срабатывает на MoveNext):

C#5 AsyncCtp BadImageFormatException

Другие источники:

person Adam Houldsworth    schedule 14.08.2012
comment
Спасибо за ссылки. Я все еще могу воспроизвести ошибку, используя код с сайта connect.microsoft.com. Я предполагаю, что у Microsoft другая интерпретация фиксированного, чем у меня. - person Bernhard Kircher; 14.08.2012
comment
@BernhardKircher Да, я тоже могу это воспроизвести. - person Adam Houldsworth; 14.08.2012
comment
@BernhardKircher Нашел еще один странный случай, на этот раз с асинхронностью, но все еще со сгенерированным кодом. - person Adam Houldsworth; 14.08.2012
comment
@BernhardKircher: Говорят, что это исправлено в сборках после VS2010, поэтому вам, возможно, придется попробовать VS2012, чтобы получить исправление. - person Jason Williams; 14.08.2012
comment
@JasonWilliams Я на самом деле этого не заметил, я изменил свой ответ. - person Adam Houldsworth; 14.08.2012
comment
+1 Я потратил на это несколько часов... Наконец-то кто-то указал на настоящую причину. - person Konrad Morawski; 09.04.2013

Убедитесь, что все ваши проекты используют один и тот же вариант компиляции (AnyCPU, x86 или x64).

Если вы используете какие-либо внешние библиотеки DLL, убедитесь, что они совместимы (т. е. 32-разрядные на компьютере с архитектурой x86 и 64-разрядные на компьютере с архитектурой x64).

Если вы хотите использовать 32-разрядные dll на машине с архитектурой x64, вам нужно будет настроить основной .exe для компиляции как «x86», а не «любой процессор», что заставит все приложение работать как 32-разрядный процесс. на 64-битном ПК. (Если вы этого не сделаете, ваш exe будет скомпилирован JIT как 64-битное приложение на машине x64, а затем попытается вызвать вашу 32-битную dll, которая вызовет исключение, которое вы получаете)

person Jason Williams    schedule 14.08.2012
comment
Решение содержит только один проект и не включает внешние библиотеки DLL. Должна быть возможность скопировать данный сценарий в один файл и запустить его. Может быть, я могу упростить сценарий... - person Bernhard Kircher; 14.08.2012