C#5 AsyncCtp BadImageFormatException

Пожалуйста, помогите мне с этим, я пишу консольное приложение, используя AsyncCtpLibrary и компилятор C#5 ctp. В первый раз, когда я действительно запустил код, который ждет, я получил это:

System.BadImageFormatException was unhandled
  Message=An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
  Source=AsyncCtpLibrary
  StackTrace:
    Server stack trace: 
       at [...].<Execute>d__1c.MoveNext()
       at [...].Execute()
       at [...].<Move>d__1d.MoveNext() in[..]:line 266
    Exception rethrown at [0]: 
       at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.<SetException>b__1(Object state)
       at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
       at System.Threading.ThreadPoolWorkQueue.Dispatch()
       at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
  InnerException: 

Мне не хватает dll, на которую можно ссылаться?

важные новинки
Мой неудачный метод выглядит так:

public async override Task<bool> Execute()
{
    //do stuff
    await stuff;
    //do other stuff
    await base.Execute()
    //do other stuff
    return true;
}

Я последовал совету Джона Скита, пытаясь постепенно воссоздать ошибку, и теперь я могу сказать, что строка await base.Execute() — убийца! Если я закомментирую эту строку, все запустится, если я оставлю ее, вызов моего метода НЕМЕДЛЕННО завершится ошибкой (не при достижении base.Execute()). Поэтому я предполагаю, что компилятор ctp делает что-то причудливое. Почему? Что я никогда не должен делать? Насколько велика ошибка?

старые вещи:

РЕДАКТИРОВАТЬ:
Что касается 32-битной/64-битной проблемы, моя система 32-битная (внутри виртуальной машины, заметьте), и, насколько мне известно, AsyncCtpLibrary.dll не содержит неуправляемого кода. Все мои проекты (библиотеки классов и отдельное консольное приложение) имеют такие вкладки сборки: screenshot
Что еще может быть не так?


РЕДАКТИРОВАТЬ: я также проверил средство просмотра Fusion log, библиотека AsyncCtpLibrary загружается без ошибок:

*** Assembly Binder Log Entry  (6/10/2011 @ 9:04:11 PM) ***    
The operation was successful.    
Bind result: hr = 0x0. The operation completed successfully.     
Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll    
Running under executable  C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\MyApp.exe

--- A detailed error log follows. 

=== Pre-bind state information ===    
LOG: User = WIN-N74LV38NLV3\Daver    
LOG: DisplayName = AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35    
 (Fully-specified)    
LOG: Appbase = file:///C:/Users/Daver/Documents/Visual Studio 2010/Projects/[...]/bin/Debug/

LOG: Initial PrivatePath = NULL    
LOG: Dynamic Base = NULL    
LOG: Cache Base = NULL    
LOG: AppName = MyApp.exe    
Calling assembly : MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===

LOG: This bind starts in default load context.    
LOG: Using application configuration file: C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\MyApp.exe.Config    
LOG: Using host configuration file:     
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.    
LOG: Post-policy reference: AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35    
LOG: GAC Lookup was unsuccessful.    
LOG: Attempting download of new URL file:///C:/Users/Daver/Documents/Visual Studio 2010/Projects/[...]/bin/Debug/AsyncCtpLibrary.DLL.    
LOG: Assembly download was successful. Attempting setup of file: C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\AsyncCtpLibrary.dll    
LOG: Entering run-from-source setup phase.    
LOG: Assembly Name is: AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35    
LOG: Binding succeeds. Returns assembly from C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\AsyncCtpLibrary.dll.    
LOG: Assembly is loaded in default load context.

Я также проверил код IL метода MoveNext() класса <Execute>d__1c, сгенерированного компилятором, и единственные сборки, на которые он ссылается ([assemblyName]), — это mscorlib, System.Core и AsyncCtpLibrary.


Я проверил манифест моей dll и AsyncCtpLibrary, мой сказал .corflags 0x00000003 // ILONLY 32BITREQUIRED, AsyncCtpLibrary сказал .corflags 0x00000009 // ILONLY, я не уверен, может ли это быть проблемой.

Пожалуйста, помогите, у меня нет идей!


person TDaver    schedule 08.06.2011    source источник


Ответы (3)


РЕДАКТИРОВАТЬ: я получил ответ от команды компилятора, которая подтвердила, что это ошибка. Это уже было исправлено в их кодовой базе, поэтому, надеюсь, мы увидим это исправление в следующем выпуске / бета-версии / CTP. Исправление не будет перенесено на «обычный» VS2010, поскольку это довольно необычный набор обстоятельств, по крайней мере, до асинхронности.


РЕДАКТИРОВАТЬ: Хорошо, теперь у меня есть очень короткая, но полная программа, которая демонстрирует проблему. Я считаю, что это смесь дженериков и вызова базового метода:

using System;
using System.Threading.Tasks;

public abstract class AsyncAction<T>
{
    public virtual Task<T> Execute()
    {
        // We never get this far
        Console.WriteLine("Execute called");
        return null;
    }
}

public class BoolAction : AsyncAction<bool>
{
    public async override Task<bool> Execute()
    {
        return await base.Execute();
    }
}

class Test
{
    static void Main()
    {
        BoolAction b = new BoolAction();
        b.Execute();
    }
}

РЕДАКТИРОВАТЬ: Хорошо, я придумал обходной путь. По сути, чтобы вызвать метод базового класса не виртуально, компилятор создает синтетический метод в BoolAction. Это немного неправильно, но мы можем исправить это:

public class BoolAction : AsyncAction<bool>
{
    public async override Task<bool> Execute()
    {
        return await BaseExecute();
    }

    private Task<bool> BaseExecute()
    {
        return base.Execute();
    }
}

Поэтому всякий раз, когда вы писали base.Execute, пишите BaseExecute и вставляйте этот дополнительный метод. Это слишком обходной путь, пока команда не исправит ошибку.

РЕДАКТИРОВАТЬ: я немного упростил пример - вам не нужны какие-либо переопределения, и, в частности, вам не нужен базовый класс для предоставления Task<T>. Вызов любого виртуального base.Foo метода сделает это:

public abstract class AsyncAction<T>
{
    public virtual T GetT()
    {
        return default(T);
    }
}

public class BoolAction : AsyncAction<bool>
{
#pragma warning disable 1998 // We're not awaiting anything
    public async void Execute()
    {
        base.GetT();
    }
#pragma warning restore 1998
}

class Test
{
    static void Main()
    {
        BoolAction b = new BoolAction();
        b.Execute();
    }
}

РЕДАКТИРОВАТЬ: вопреки моим предыдущим мыслям, это также действительно влияет на итераторы. Асинхронная CTP не требуется...

public abstract class Base<T>
{
    public virtual T GetT()
    {
        return default(T);
    }
}

public class Derived : Base<bool>
{
    public System.Collections.IEnumerator Foo()
    {
        base.GetT();
        yield break;
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        d.Foo().MoveNext();
    }
}

РЕДАКТИРОВАТЬ: И это также влияет на анонимные функции...

using System;

public abstract class Base<T>
{
    public virtual T GetT()
    {
        return default(T);
    }
}

public class Derived : Base<bool>
{
    public void Foo()
    {
        Action x = () => base.GetT();
        x();
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        d.Foo();
    }
}
person Jon Skeet    schedule 11.06.2011
comment
Мой неудачный метод заключается в публичном асинхронном переопределении Task‹bool› Execute(), который делает что-то (последовательно), затем иногда запрашивает ввод данных пользователем (из консоли), а затем возвращает true или false. Возможно ли, что переопределение как-то связано с этим? - person TDaver; 11.06.2011
comment
@TDaver: Я бы этого не ожидал, нет ... но если вы можете попытаться максимально уменьшить его, пока у вас не будет минимального неудачного примера, это действительно поможет. - person Jon Skeet; 11.06.2011
comment
@TDaver: Ага, намного лучше. Я могу понять, почему это вызывает проблему ... Я попытаюсь отредактировать свой пост с помощью короткой, но полной программы, чтобы показать это. - person Jon Skeet; 11.06.2011
comment
@TDaver: Хм... Я пытался воспроизвести это, но у меня все еще работает. Кстати, какую версию CTP вы используете? Последний, который работает с VS 2010 SP1? - person Jon Skeet; 11.06.2011
comment
Да, этот... Кроме того, если это поможет, мой base.Execute() - это TaskCompletionSource внизу (тот, на который вы ответили ранее в stackoverflow.com/questions/6145246/how-to-write-c-5-async) - person TDaver; 11.06.2011
comment
@TDaver: Хм... хорошо, для меня это определенно звучит как ошибка. Вы можете отправить мне код, чтобы я помог сократить его до короткого, но полного примера, который мы можем отправить команде? - person Jon Skeet; 11.06.2011
comment
Должен ли я отправить вам dll? Я не могу найти ничего явно неправильного в IL, но тогда я даже не могу найти базовый вызов в сгенерированном классе MoveNext() :) - person TDaver; 11.06.2011

Вы сталкиваетесь с известной ошибкой VS 2010

https://connect.microsoft.com/VisualStudio/feedback/details/626550/badimageformateception-on-simple-program-using-generics-and-lambdas

person Marek Safar    schedule 14.06.2011

Это исключение часто возникает, когда вы пытаетесь загрузить 32-битную DLL в 64-битной среде.

Если вы работаете в 64-битной ОС, попробуйте изменить настройки проектов, чтобы они компилировались непосредственно для x86 (а не для AnyCPU).

(Это может звучать наоборот, но это потому, что если вы загружаете внешнюю 32-битную DLL, вам нужно сделать весь проект 32-битным.)

person Simon P Stevens    schedule 08.06.2011
comment
Я установил для всех своих проектов Build Target значение x86 в свойствах каждого проекта. Ничего не изменилось. :( - person TDaver; 09.06.2011
comment
также я не думаю, что работаю в 64-битной среде - person TDaver; 09.06.2011
comment
Я даже пытался установить целевую структуру на полный .net4, все равно не помогло. - person TDaver; 09.06.2011
comment
@TDaver: Извините, я не знаю, что еще может быть. - person Simon P Stevens; 09.06.2011
comment
Когда я попытался запустить явно в x64, я не могу запустить, система не поддерживает 64-битную систему, поэтому да, я в 32-битном режиме. Когда я работаю в режиме x86 или Any CPU, я получаю вышеупомянутое исключение. - person TDaver; 09.06.2011
comment
@Simon P Stevens: я обновил свой вопрос, пожалуйста, проверьте его, если он даст вам какие-либо идеи. - person TDaver; 09.06.2011