Search code examples
c#.netlinqcode-analysisreflector

Goto in the ElementAt extension method


I was looking some code generated by .NET Reflector of the Linq extension method ElementAt, and I see this code:

public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index)
{
    TSource current;
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
    Label_0036:
        if (!enumerator.MoveNext())
        {
            throw Error.ArgumentOutOfRange("index");
        }
        if (index == 0)
        {
            current = enumerator.Current;
        }
        else
        {
            index--;
            goto Label_0036;
        }
    }
    return current;
}

I think you can write the same thing without a goto statement. Something like:

public static TSource ElementAtBis<TSource>(this IEnumerable<TSource> source, int index)
{
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            if (index == 0)
            {
                return enumerator.Current;
            }
            else
            {
                index--;
            }
        }
        throw new ArgumentOutOfRangeException("index");
    }
}

So I am wondering why the ElementAt was written this way. Is there some kind of conventions here? Maybe the rule is to have only one return statement that much be the last line of the function? Or maybe I'm missing something about performance? Or is this the .NET Reflector which have a problem?

As a side note, the method ElementAtOrDefault doesn't use a goto statement:

public static TSource ElementAtOrDefault<TSource>(this IEnumerable<TSource> source, int index)
{
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            if (index == 0)
            {
                return enumerator.Current;
            }
            index--;
        }
    }
    return default(TSource);
}

Solution

  • It's all the matter of decompiler. Next code is produced by decompiling mscorlib assembly's method ElementAt by DotPeek:

    public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index)
    
    //...omitted code for validation
    
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
       while (enumerator.MoveNext())
       {
          if (index == 0)
             return enumerator.Current;
          --index;
       }
       throw Error.ArgumentOutOfRange("index");
    }
    

    IL instructions doesn't have while construction. Next code demonstrates this:

    while(true)
    {
        Console.WriteLine ("hi there");
    }
    

    is compiled into:

    IL_0000:  ldstr       "hi there"
    IL_0005:  call        System.Console.WriteLine
    IL_000A:  br.s        IL_0000    //unconditionaly transfers control to IL_0000. It's like goto IL_0000; but in IL