Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would one define a local function in C# just to call it right away (in context of IEnumerable<T>) [duplicate]

I had a look at the implementation of several extension methods of the genious MoreLINQ- project. And I came across a style habit that I cannot explain. Maybe some of you can?

It happens for example in Pairwise.cs, cited below.

So why would the author author a local function named _() just to call it in the return expression? Wouldn't it be straight forward just to implement the yield return/yield break in the very function? My suspicion is that it has something to do with the way the compiler generates the Enumerator-object off the yield implementation. But I don't see a difference. Actually there is even some closure-ing happening - I regard that as even worse (!?)
Edit: No, it should not be closured, because it is not a lambda but a local function which will just grab the outer scope variables whatever they are.

    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;
                }
            }
        }
    }
like image 314
Robetto Avatar asked Oct 27 '25 06:10

Robetto


1 Answers

It's to make argument validation eager but allow the rest of the method to be written using yield. With it, you get an exception relating to the arguments at the point at which you call Pairwise<TSource, TResult>.

Without it, you'd get the exception when you first call MoveNext on the returned enumerator.

like image 189
Damien_The_Unbeliever Avatar answered Oct 29 '25 08:10

Damien_The_Unbeliever