Какой конкретный тип возвращает доходность?

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

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

person stacker    schedule 11.08.2010    source источник
comment
Это синтаксический сахар. многое происходит под капотом. Более быстрый способ увидеть это — использовать отражатель. По сути, он создает класс, который сохраняет состояние и возвращает a, когда вызывается GetNext() или что-то в этом роде.   -  person Hamish Grubijan    schedule 11.08.2010
comment
@Timwi спасибо за редактирование :)   -  person stacker    schedule 11.08.2010


Ответы (3)


Это тип, созданный компилятором. Компилятор генерирует реализацию 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>.

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

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

person Dan Tao    schedule 11.08.2010
comment
Кроме того, в вашем примере сгенерированный компилятором тип будет иметь имя <GetIEnumerable>d__0. (Да, < и > являются частью имени типа. Вы не можете написать такое имя типа в C#, но оно допустимо в CLR.) Тип вложен внутри типа, который объявляет метод GetIEnumerable(). - person Timwi; 11.08.2010

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

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

person SLaks    schedule 11.08.2010
comment
Пожалуйста, добавьте соответствующие части ссылки к вашему ответу - person Fund Monica's Lawsuit; 19.06.2016

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

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

Отпечатки:

YourClass+<GetIEnumerable>d__0
person Thomas Levesque    schedule 11.08.2010