IEnumerable перечисляется при вызове метода или при перечислении ответа

Я хочу знать, что параметр IEnumerable для метода перечисляется при вызове метода или при перечислении возврата метода, при условии, что у нас есть следующий код:

IEnumerable<T> ProcessList(IEnumerable<T> list)
{
    foreach(var element in list)
    {
        yield return ProcessElement(element);
    }
}

Мне в основном любопытно, как писать Where-Linq как расширения.

2 ответа

Решение

list (enumerable) перечисляется только тогда, когда результат ProcessList (enum2) перечислено:

static void Main(string[] args)
{
    var enumerable = Enum1();
    Console.WriteLine("Enum1 retrieved");
    var enum2 = Enum2(enumerable);
    Console.WriteLine("Enum2 called");
    foreach (var e in enum2)
    {
        Console.WriteLine(e);
    }
}

private static IEnumerable<string> Enum1()
{
    Console.WriteLine("Enum1");
    yield return "foo";
}

private static IEnumerable<string> Enum2(IEnumerable<string> enumerable)
{
    Console.WriteLine("Enum2");
    foreach (var s in enumerable)
    {
        yield return s;
    }
}

дает:

Enum1 retrieved
Enum2 called
Enum2
Enum1
foo

Последние три строки печатаются только при вводе foreach петля.

Использование yield Ключевое слово означает, что этот фрагмент кода будет оцениваться только по мере необходимости для предоставления результатов, которые вы используете. Другими словами, это не приведет к оценке:

var processed = ProcessList(unprocessed);

Содержимое списка результатов не имеет значения, поэтому они еще не будут оценены. Однако, если вы сделаете это:

var processed = ProcessList(unprocessed).ToList();

это попросит его оценить IEnumerable, что приведет к запуску вашего кода. Аналогично, если вы сделаете это:

var processed = ProcessList(unprocessed);
foreach (var x in processed)
{
    DoSomething(x);
}

это будет работать ваш ProcessElement() метод для каждого элемента по очереди. Чтобы сделать это дальше, если вы делаете это:

var processed = ProcessList(unprocessed);
foreach (var x in processed.Take(10))
{
    DoSomething(x);
}

поскольку вы используете только первые 10 элементов списка результатов, он будет запускать только ProcessElement() метод для тех 10. Остальные будут оцениваться только тогда, когда вы их используете.

Другие вопросы по тегам