C#5异步Ctp BadImageFormatException

5

请帮我翻译这个问题,我正在使用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;
}

我遵循了Jon Skeet的建议,试图逐步重现错误,现在我可以确定,await base.Execute()这一行是致命的!如果我将该行注释掉,一切都可以运行,如果我留下它,调用我的方法会立即失败(而不是在到达base.Execute()时)。所以我认为ctp编译器做了一些奇怪的事情。为什么?我应该永远不要做什么?这个bug有多大?

旧内容:

编辑:
至于32位/64位问题,我的系统是32位的(在虚拟机内),据我所知AsyncCtpLibrary.dll不包含非托管代码。所有我的项目(类库和单个控制台应用程序)都有像这样的构建选项卡:screenshot
可能还有什么问题吗?


编辑: 我还检查了Fusion日志查看器,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.

我也检查了由编译器生成的 <Execute>d__1c 类的 MoveNext() 方法的IL代码,它所引用的程序集([assemblyName])仅有mscorlib、System.Core和AsyncCtpLibrary。
我检查了我的dll和AsyncCtpLibrary的清单,我的清单中写着.corflags 0x00000003 // ILONLY 32BITREQUIRED,而AsyncCtpLibrary则写着.corflags 0x00000009 // ILONLY,我不确定这是否可能是问题所在。
请帮帮我,我已经没有更多的想法了!
3个回答

6

编辑:我已经收到编译器团队的回复,他们确认这是一个错误。在他们的代码库中已经修复了这个问题,所以希望我们能在下一个发布/测试版/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并插入该额外的方法。这不是一个太糟糕的解决方法,直到团队修复这个bug。
编辑:我已经简化了示例 - 您不需要任何覆盖,并且特别是您不需要基类公开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();
    }
}

我的失败方法是公共的异步覆盖任务<bool> Execute(),它执行一些操作(按顺序),然后有时会要求用户输入(来自控制台),然后返回true或false。覆盖可能与此有关吗? - TDaver
@TDaver:啊哈,好多了。我可以理解为什么会造成问题。我会尝试编辑我的帖子,并添加一个简短但完整的程序来展示它。 - Jon Skeet
@TDaver:嗯...我尝试复现了这个问题,但是对我来说一切都还正常。顺便问一下,您使用的是哪个版本的CTP呢?是最近那个能与VS 2010 SP1配合使用的吗? - Jon Skeet
@TDaver:嗯...好的,这听起来肯定是个bug。你能给我发一些代码吗?这样我就可以帮助你将其缩减为一个简短但完整的示例,我们可以将其发送给团队。 - Jon Skeet
我应该把dll发送给你吗?我在IL中没有发现任何明显的问题,但是我甚至在生成的类的MoveNext()中找不到基本调用 :) - TDaver
显示剩余2条评论


0

当您尝试在64位环境中加载32位DLL时,通常会出现此异常。

如果您正在运行64位操作系统,请尝试更改项目设置以直接编译为x86(而不是AnyCPU)。

(这可能听起来有些反向,但这是因为如果您加载外部32位DLL,则需要强制整个项目为32位。)


我已将所有项目的构建目标设置为x86,在每个项目的属性中。但是没有任何变化。:( - TDaver
我也不认为我正在运行64位环境。 - TDaver
我甚至尝试将目标框架设置为完整的.NET 4,但仍然没有帮助。 - TDaver
@TDaver:那我很抱歉,我不知道还有什么其他原因了。 - Simon P Stevens
当我尝试在x64上显式运行时,出现了“无法运行,系统不支持64位”的错误,所以我处于32位模式。当我在x86或任何CPU模式下运行时,我会得到上述异常。 - TDaver
@Simon P Stevens:我已经更新了我的问题,请查看一下,如果有任何想法请告诉我。 - TDaver

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