Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use wrappers around the actual iterator functions in LINQ extension methods?

Tags:

iterator

c#

linq

When looking at Microsoft's implementation of various C# LINQ methods, I noticed that the public extension methods are mere wrappers that return the actual implementation in the form of a separate iterator function.

For example (from System.Linq.Enumerable.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; 
}

What is the reason for wrapping the iterator like that instead of combining them into one and return the iterator directly?

Like this:

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; 
}
like image 929
hjort Avatar asked Mar 30 '17 10:03

hjort


1 Answers

Wrappers are used to check method arguments immediately (i.e. when you call LINQ extension method). Otherwise arguments will not be checked until you start to consume iterator (i.e. use query in foreach loop or call some extension method which executes query - ToList, Count etc). This approach is used for all extension methods with deferred type of execution.

If you will use approach without wrapper then:

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

With argument-checking wrapper method you will get exception at first.Concat(second) line.

like image 91
Sergey Berezovskiy Avatar answered Nov 14 '22 22:11

Sergey Berezovskiy