Зачем использовать обертки вокруг фактических функций итератора в методах расширения LINQ?

рассматривая реализацию Microsoft различных методов C# LINQ, я заметил, что методы открытого расширения являются простыми оболочками, которые возвращают фактическую реализацию в виде отдельной функции итератора.

например (из системы.В LINQ.Перечислимый.cs):

public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) {
    if (first == null) throw Error.ArgumentNull("first");
    if (second == null) throw Error.ArgumentNull("second");
    return ConcatIterator<TSource>(first, second); 
}

static IEnumerable<TSource> ConcatIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second) { 
    foreach (TSource element in first) yield return element;
    foreach (TSource element in second) yield return element; 
}

в чем причина обертывания итератора, вместо того, чтобы объединять их в один и возвращать итератор напрямую?

такой:

public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) {
    if (first == null) throw Error.ArgumentNull("first");
    if (second == null) throw Error.ArgumentNull("second");
    foreach (TSource element in first) yield return element;
    foreach (TSource element in second) yield return element; 
}

1 ответов


обертки используются для немедленной проверки аргументов метода (т. е. при вызове метода расширения LINQ). В противном случае аргументы не будут проверены, пока вы не начнете использовать итератор (т. е. использовать запрос в цикле foreach или вызвать некоторый метод расширения, который выполняет query - ToList, Count и т. д.). Этот подход используется для всех методов расширения с отложенным типом выполнения.

Если вы будете использовать подход без обертки, то:

int[] first = { 1, 2, 3 };
int[] second = null;

var all = first.Concat(second); // note that query is not executed yet
// some other code
...
var name = Console.ReadLine();
Console.WriteLine($"Hello, {name}, we have {all.Count()} items!"); // boom! exception here

с оберткой для проверки аргументов метод вы получите исключение при first.Concat(second) линии.