Какой конкретный тип возвращает 'yield return'? - PullRequest
9 голосов
/ 11 августа 2010

Какой тип бетона для этого IEnumerable<string>?

private IEnumerable<string> GetIEnumerable()
{
    yield return "a";
    yield return "a";
    yield return "a";
}

Ответы [ 3 ]

8 голосов
/ 11 августа 2010

Это тип, сгенерированный компилятором. Компилятор генерирует реализацию IEnumerator<string>, которая возвращает три значения «a», и класс скелета IEnumerable<string>, который предоставляет одно из них в своем методе GetEnumerator.

Сгенерированный код выглядит что-то вот так *:

// No idea what the naming convention for the generated class is --
// this is really just a shot in the dark.
class GetIEnumerable_Enumerator : IEnumerator<string>
{
    int _state;
    string _current;

    public bool MoveNext()
    {
        switch (_state++)
        {
            case 0:
                _current = "a";
                break;
            case 1:
                _current = "a";
                break;
            case 2:
                _current = "a";
                break;
            default:
                return false;
        }

        return true;
    }

    public string Current
    {
        get { return _current; }
    }

    object IEnumerator.Current
    {
        get { return Current; }
    }

    void IEnumerator.Reset()
    {
        // not sure about this one -- never really tried it...
        // I'll just guess
        _state = 0;
        _current = null;
    }
}

class GetIEnumerable_Enumerable : IEnumerable<string>
{
    public IEnumerator<string> GetEnumerator()
    {
        return new GetIEnumerable_Enumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Или, может быть, как SLaks говорит в своем ответе, две реализации заканчиваются в одном классе. Я написал это на основе изменчивой памяти сгенерированного кода, на которую смотрел раньше; на самом деле, одного класса будет достаточно, поскольку нет причин, по которым вышеуказанная функциональность требует двух.

На самом деле, если задуматься, две реализации на самом деле должны находиться в одном классе, так как я только что вспомнил, что функции, использующие операторы yield, должны иметь тип возврата или IEnumerable<T> или IEnumerator<T>.

В любом случае, я позволю вам внести исправления кода в то, что я написал мысленно.

* Это исключительно для иллюстрации; Я не претендую на его реальную точность. Это всего лишь общая демонстрация того, как компилятор делает то, что он делает, основываясь на доказательствах, которые я видел в своих собственных исследованиях.

7 голосов
/ 11 августа 2010

Компилятор автоматически сгенерирует класс, который реализует как IEnumerable<T>, так и IEnumerator<T> (в одном классе).

У Джона Скита есть подробное объяснение .

2 голосов
/ 11 августа 2010

Конкретная реализация IEnumerable<string>, возвращаемая методом, представляет собой анонимный тип, сгенерированный компилятором

Console.WriteLine(GetIEnumerable().GetType());

Отпечатки:

YourClass+<GetIEnumerable>d__0
...