【问题标题】:C#5 AsyncCtp BadImageFormatExceptionC#5 AsyncCtp BadImageFormatException
【发布时间】:2011-09-11 03:16:32
【问题描述】:

请帮我解决这个问题,我一直在使用 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 不包含非托管代码。我所有的项目(类库和单控制台应用程序)都有这样的构建选项卡:
可能还有什么问题?


编辑: 我还检查了 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.

我还检查了&lt;Execute&gt;d__1c 编译器生成的类的 MoveNext() 方法的 IL 代码,它引用的唯一程序集 ([assemblyName]) 是 mscorlib、System.Core 和AsyncCtpLibrary。


我检查了我的 dll 和 AsyncCtpLibrary 的 ma​​nifest,我说 .corflags 0x00000003 // ILONLY 32BITREQUIRED,AsyncCtpLibrary 说 .corflags 0x00000009 // ILONLY,我不确定这是否是问题所在。

请帮忙,我没办法了!

【问题讨论】:

    标签: async-await c#-5.0


    【解决方案1】:
    【解决方案2】:

    编辑:我收到了编译器团队的回复,他们确认这是一个错误。它已经在他们的代码库中修复了,所以希望我们能在下一个版本/beta/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&lt;T&gt;。调用 any virtual 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();
        }
    }
    

    【讨论】:

    • 我的失败方法是公共异步覆盖任务 Execute(),它(按顺序)做一些事情,然后有时要求用户输入(从控制台)然后返回真或假。覆盖是否可能与此有关?
    • @TDaver:我不希望如此,不......但如果你能尽量减少它,直到你有一个最小的失败例子,那真的很有帮助。
    • @TDaver:啊哈,好多了。我可以理解为什么会导致问题...我会尝试用一个简短但完整的程序来编辑我的帖子以显示它。
    • @TDaver: 嗯...我试图重现这个,但它仍然对我有用。顺便问一下,您使用的是哪个版本的 CTP?最近一个与 VS 2010 SP1 一起工作的?
    • 是的,那个...另外,如果这有帮助,我的 base.Execute() 是下面的 TaskCompletionSource(你之前在 stackoverflow.com/questions/6145246/how-to-write-c-5-async 中回答的那个)
    【解决方案3】:

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

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

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

    【讨论】:

    • 我已在每个项目的属性中将所有项目的构建目标设置为 x86。没有改变。 :(
    • 我也不认为我在运行 64 位环境
    • 我什至尝试将目标框架设置为完整的.net4,仍然没有帮助
    • @TDaver:那么抱歉,我不知道还能是什么。
    • 当我尝试在 x64 中显式运行时,我得到“无法运行,系统不支持 64 位”所以是的,我处于 ​​32 位模式。当我在 x86 或任何 CPU 模式下运行时,我得到了上述异常。
    猜你喜欢
    • 2013-04-01
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多