Блоки итераторов и наследование - PullRequest
16 голосов
/ 12 марта 2010

Имеется базовый класс со следующим интерфейсом:

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

Однако меня приветствует предупреждение о том, что «доступ к члену через базовое ключевое слово от итератора не может быть проверен».

Каково тогда принятое решение этой проблемы?

Ответы [ 4 ]

12 голосов
/ 12 марта 2010

Как насчет:

public class Derived : Base
{
    public override IEnumerable<string> GetListOfStuff()
    {
        return base.GetListOfStuff().Concat(GetMoreStuff());        
    }
    private IEnumerable<string> GetMoreStuff()
    {
        yield return "Fourth";
        yield return "Fifth";
    }
}
9 голосов
/ 12 марта 2010

Кстати, причина такого странного поведения заключается в том, что группа безопасности CLR изменила верификатор непосредственно перед отправкой v2, так что стало невозможно проверить не виртуальный вызов виртуального метода одного класса из метода другого класс.

Подробнее об этой проблеме см. Мою статью на эту тему несколько лет назад.

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

Это уже устарело; мы исправили компилятор, чтобы он теперь генерировал для вас помощник.

4 голосов
/ 12 марта 2010

Кажется, что одним из решений было просто следовать указаниям «руководства» : создать вспомогательную функцию.

Итак, пока я решил это так:

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 голосов
/ 12 марта 2010

Это потому, что итератор превращается в закрытый класс, а доступ к методам суперкласса из внутреннего класса не поддается проверке (так как он должен принудительно указывать указатель this на что-то, кроме себя).

Попробуйте создать новый приватный метод в Derived:

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

и назовите это вместо base.GetListOfStuff()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...