使用 Visual Studio 2010 编译时覆盖通用迭代器导致 BadImageFormatException

Overriding generic iterator results in BadImageFormatException when compiled with Visual Studio 2010

tl;博士:

如何避免这种情况?


问题描述

When stepping into in in Main in the code in the code in MVCE below (which would normally move the execution to the iterator method), a BadImageFormatException throw when the code is compiled in Visual Studio 2010:

但不在 Visual Studio 2012 年及以上:


MCVE

public class Program
{
    public static void Main(string[] args)
    {
        foreach ( var item in new ScrappyDoo().GetIEnumerableItems() )
            Console.WriteLine(item.ToString());
    }
}

public class ScoobyDoo<T>
    where T : new()
{
    public virtual IEnumerable<T> GetIEnumerableItems()
    {
        yield return new T();
    }
}

public class ScrappyDoo : ScoobyDoo<object>
{
    public override IEnumerable<object> GetIEnumerableItems()
    {
        foreach ( var item in base.GetIEnumerableItems() )
            yield return item;
    }
}

注意事项


我的实际问题

有人知道这是为什么吗?如何避免?对于我的实际用例,基础中的迭代器中没有任何项目,所以我制作了基础方法 abstract 并使所有派生的 classes 覆盖它,但这可能随时改变,渲染hack 修复无用。

解决此问题的三个建议不需要完全放弃迭代器,所有这些建议都依赖于让 VS 了解基础和派生 return 类型的 "discrepancy",这似乎是麻烦的根源。

将迭代器实现移动到不是 virtual/overridden

的方法
public override IEnumerable<object> GetIEnumerableItems()
{
    return getIEnumerableItems();
}

IEnumerable<object> getIEnumerableItems() 
{
    foreach ( var item in base.GetIEnumerableItems() )
        yield return item;
}

将基本调用移出迭代器,显而易见的方式

public override IEnumerable<object> GetIEnumerableItems()
{
    foreach ( var item in baseItems() )
    {
        yield return item;
    }
}

IEnumerable<object> baseItems() 
{
    return base.GetIEnumerableItems();
}

这可能会因内联而受阻,但我认为编译器不会打扰(传统上此类事情留给 IL 级别)。

将基本调用移出迭代器,涉及的方式

public override IEnumerable<object> GetIEnumerableItems()
{
    return getIEnumerableItems(base.GetIEnumerableItems());
}

IEnumerable<object> getIEnumerableItems(IEnumerable<object> baseItems) 
{
    foreach ( var item in baseItems )
        yield return item;
}

免责声明:none 由于没有安装 VS 2010,因此已经过测试。