Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterator blocks and inheritance

Given a base class with the following interface:

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

I want to make a derived class that overrides the method, and adds its own stuff, like so:

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

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

However, I'm greeted with a warning that "access to a member through a base keyword from an iterator cannot be verified".

What's the accepted solution to this problem then?

like image 309
Dave Van den Eynde Avatar asked Mar 12 '10 13:03

Dave Van den Eynde


4 Answers

How about:

public class Derived : Base
{
    public override IEnumerable<string> GetListOfStuff()
    {
        return base.GetListOfStuff().Concat(GetMoreStuff());        
    }
    private IEnumerable<string> GetMoreStuff()
    {
        yield return "Fourth";
        yield return "Fifth";
    }
}
like image 174
Marc Gravell Avatar answered Oct 02 '22 15:10

Marc Gravell


Incidentally, the reason for this odd behaviour is that the CLR security team changed the verifier right before v2 shipped, such that it became unverifiable to do a non-virtual call on a virtual method of one class from a method in a different class.

For further explanation of this issue see my article on the subject from a few years back.

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

This is now out-of-date; we've fixed up the compiler so that it now generates the helper for you.

like image 28
Eric Lippert Avatar answered Oct 02 '22 15:10

Eric Lippert


It seems that one solution was to simply follow what the "manual" says: make a helper function.

So for now I've solved it like this:

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";
    }
}

But I'm curious about other solutions as well, should they exist.

like image 44
Dave Van den Eynde Avatar answered Oct 02 '22 15:10

Dave Van den Eynde


It's because the iterator gets turned into a private class, and accessing superclass methods from an inner class is not verifiable (as it has to force the 'this' pointer to something other than itself).

Try creating a new private method in Derived:

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

and call that instead of base.GetListOfStuff()

like image 43
thecoop Avatar answered Oct 02 '22 16:10

thecoop