Question

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);
}
Was it helpful?

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

OTHER TIPS

I think its the .Net Reflector that has decompiled the code like that, the original code from here doesn't have any goto

 public static TSource ElementAt</tsource,><tsource>(this IEnumerable</tsource><tsource> source, int index) {
            if (source == null) throw Error.ArgumentNull("source");
            IList</tsource><tsource> list = source as IList</tsource><tsource>;
            if (list != null) return list[index];
            if (index < 0) throw Error.ArgumentOutOfRange("index");
            using (IEnumerator</tsource><tsource> e = source.GetEnumerator()) {
                while (true) {
                    if (!e.MoveNext()) throw Error.ArgumentOutOfRange("index");
                    if (index == 0) return e.Current;
                    index--;
                }
            }
        }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top