sha*_*are 5 .net linq-to-objects exception
我在下面的这个小代码中遇到了BadImageFormatException错误.我知道以这种方式编写程序并不是一个好习惯,但它似乎是.NET Framework中的一个错误,而不是我的代码.
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var b = new B();
            var bb = b.Test();
            var bbb = bb.Count();
        }
    }
    class A<T>
    {
        public virtual IEnumerable<T> Test()
        {
            yield return default(T);
        }
    }
    class B : A<int>
    {
        public IEnumerable<int> Test()
        {
            base.Test();
            yield return 0;
        }
    }
}
任何想法为什么它不起作用?
作为旁注,您应该将B.Test()方法声明为重写,但这是一个不同的问题。
注释掉该行base.Test();可以修复它。这是我的理论。
问题是您正在B.Test()使用编译器生成的迭代器来实现。该过程的一部分是获取代码并使用私有嵌套类创建状态机。编译器团队似乎没有想到您会调用迭代器中任何内容的基本实现的用例。
所以实际上你的代码是这样的:
class B : A<int>
{
    public override IEnumerable<int> Test()
    {
        base.Test();
        yield return 0;
    }
}
将需要编译器创建的迭代器,并将转换您的行以创建适当的状态机。它无法识别该base调用,因此它一定是逐字复制的。生成的类自然不会从任何其他类继承,因此base调用将失败。从概念上讲,状态机代码将在某处包含以下行:
[CompilerGenerated]
private sealed class <Test>d__0 : IEnumerable<T>, IEnumerable, IEnumerator<T>, IEnumerator, IDisposable
{
    bool MoveNext()
    {
        // ...
        base.Test(); // what, base?
        // ...
    }
}
尽管查看使用 Reflector 生成的代码,但它实际上并没有出现在程序集中(至少我没有看到它)。
我编写了一个不同的测试用例来确定哪一行导致了问题:
System.Console.WriteLine("Starting");
using (var e = bb.GetEnumerator())
{
    System.Console.WriteLine(e.MoveNext());
    System.Console.WriteLine(e.Current);
    System.Console.WriteLine(e.MoveNext());
}
并单步执行代码。它在第一次MoveNext()调用时失败(正如我所想的那样)。不幸的是我不知道如何进入生成的迭代器。因此,单步执行反汇编代码,它在标记行上失败:
            System.Console.WriteLine("Starting");
00000075  mov         ecx,dword ptr ds:[03622088h] 
0000007b  call        63474D1C 
00000080  nop 
            using (var e = bb.GetEnumerator())
00000081  mov         ecx,dword ptr [ebp-44h] 
00000084  call        dword ptr ds:[001E0020h] 
0000008a  mov         dword ptr [ebp-58h],eax 
0000008d  mov         eax,dword ptr [ebp-58h] 
00000090  mov         dword ptr [ebp-48h],eax 
            {
00000093  nop 
                System.Console.WriteLine(e.MoveNext());
00000094  mov         ecx,dword ptr [ebp-48h] 
00000097  call        dword ptr ds:[001E0024h]     // ERROR!!!!!!!!!!!!!!!!
0000009d  mov         dword ptr [ebp-5Ch],eax 
000000a0  mov         ecx,dword ptr [ebp-5Ch] 
000000a3  call        63A48640 
000000a8  nop 
                System.Console.WriteLine(e.Current);
000000a9  mov         ecx,dword ptr [ebp-48h] 
000000ac  call        dword ptr ds:[001E0028h] 
000000b2  mov         dword ptr [ebp-60h],eax 
000000b5  mov         ecx,dword ptr [ebp-60h] 
000000b8  call        63A49388 
000000bd  nop 
因此,也许实际的问题可能是其他问题,但可能与此base调用有关。