Unexpected pattern #837
-
While peeking at the code of MoreLinq, I've spotted more than once a code construct for which I fail to identify the reason of being. An example is the implementation of public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TResult> resultSelector)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
return _(); IEnumerable<TResult> _()
{
using var e = source.GetEnumerator();
if (!e.MoveNext())
yield break;
var previous = e.Current;
while (e.MoveNext())
{
yield return resultSelector(previous, e.Current);
previous = e.Current;
}
}
} but I have also seen it in The question is: why define a local lambda public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TResult> resultSelector)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
using var e = source.GetEnumerator();
if (!e.MoveNext())
yield break;
var previous = e.Current;
while (e.MoveNext())
{
yield return resultSelector(previous, e.Current);
previous = e.Current;
}
} Thanks in advance! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 12 replies
-
The local lambda in this case is an iterator method. So, what this pattern achieves is immediate argument validation while maintaining LINQ's deferred execution. You can try running this code yourself on both versions to see the difference:
I have a relevant (and longer) post focusing on the async versions of these issues: https://blog.i3arnon.com/2021/07/12/async-linq-operator/ |
Beta Was this translation helpful? Give feedback.
-
This is a pattern you will find even in the .net runtime in the enumerable methods. The most important thing to realize is that if you do a Example consumer code: var data = source.Pairwise(null);
// Do something else
return data; Under the default version (what you provided), then the |
Beta Was this translation helpful? Give feedback.
-
While @viceroypenguin and @i3arnon have provided excellent insights already, see also my answer to the question “Can anyone explain this enumerator syntax?” on StackOveflow. The new parameter null-checking syntactic sugar ( |
Beta Was this translation helpful? Give feedback.
This is a pattern you will find even in the .net runtime in the enumerable methods. The most important thing to realize is that if you do a
yield return
, none of the code in the method will run until the first time the consumer actually enumerates the data. This means that arguments are not checked immediately in the normal method. Doing the local method pattern allows for immediate argument validation while still using theyield return
pattern.Example consumer code:
Under the default version (what you provided), then the
null
argument will not be checked in this method, but will be checked when the caller tries to use…