迭代器块和继承

时间:2010-03-12 13:01:15

标签: c# inheritance iterator

给定具有以下接口的基类:

public class Base
{
    public virtual IEnumerable<string> GetListOfStuff()
    {
        yield return "First";
        yield return "Second";
        yield return "Third";
    }
}

我想创建一个覆盖该方法的派生类,并添加自己的东西,如下所示:

public class Derived : Base
{
    public override IEnumerable<string> GetListOfStuff()
    {
        foreach (string s in base.GetListOfStuff())
        {
            yield return s;
        }

        yield return "Fourth";
        yield return "Fifth";
    }
}

但是,我受到了警告,“无法验证通过迭代器中的base关键字访问成员”。

那么这个问题的解决方案是什么?

5 个答案:

答案 0 :(得分:12)

怎么样:

public class Derived : Base
{
    public override IEnumerable<string> GetListOfStuff()
    {
        return base.GetListOfStuff().Concat(GetMoreStuff());        
    }
    private IEnumerable<string> GetMoreStuff()
    {
        yield return "Fourth";
        yield return "Fifth";
    }
}

答案 1 :(得分:9)

顺便提一下,这种奇怪行为的原因是CLR安全团队在v2发布之前就更改了验证程序,因此从一个不同的方法对一个类的虚方法进行非虚拟调用变得无法验证类。

有关此问题的进一步说明,请参阅几年前关于此主题的文章。

http://blogs.msdn.com/ericlippert/archive/2005/11/14/why-are-base-class-calls-from-anonymous-delegates-nonverifiable.aspx

这已经过时了;我们已经修复了编译器,现在它为你生成帮助器。

答案 2 :(得分:4)

似乎一个解决方案就是简单地遵循"manual"所说的:做一个辅助函数。

所以现在我已经解决了这个问题:

public class Derived : Base
{
    private IEnumerable<string> GetBaseStuff()
    {
        return base.GetListOfStuff();
    }

    public override IEnumerable<string> GetListOfStuff()
    {
        foreach (string s in GetBaseStuff())
        {
            yield return s;
        }

        yield return "Fourth";
        yield return "Fifth";
    }
}

但是如果存在其他解决方案我也很好奇。

答案 3 :(得分:3)

这是因为迭代器变成了一个私有类,并且从内部类访问超类方法是不可验证的(因为它必须强制'this'指针指向除了它自己之外的东西)。

尝试在Derived中创建一个新的私有方法:

private IEnumerable<string> GetBaseListOfStuff()
{        
    return base.GetListOfStuff();
}

并调用而不是base.GetListOfStuff()

答案 4 :(得分:-1)

以防万一有人仍在寻找答案。遇到了同样的问题,并且能够通过这样做来使其正常工作:

public class Derived : Base
{
    public override IEnumerable<string> GetListOfStuff()
    {
        var enumerator = base.GetListOfStuff().GetEnumerator();

        while(enumerator.MoveNext())
        {
             yield return enumerator.Current;
        }

        yield return "Fourth";
        yield return "Fifth";

        yield break;
    }
}