【问题标题】:Goto in the ElementAt extension methodElementAt 扩展方法中的 Goto
【发布时间】:2013-05-15 09:31:59
【问题描述】:

我正在查看由 Linq 扩展方法 ElementAt.NET Reflector 生成的一些代码,我看到了这段代码:

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;
}

我认为您可以在没有 goto 语句的情况下编写相同的内容。类似的东西:

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");
    }
}

所以我想知道为什么 ElementAt 是这样写的。这里有某种约定吗?也许规则是只有一个返回语句是函数的最后一行?或者也许我错过了一些关于性能的东西?或者这是有问题的.NET Reflector?

附带说明,ElementAtOrDefault 方法不使用 goto 语句:

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);
}

【问题讨论】:

  • C# while 关键字只不过是goto 指令的语法糖。

标签: c# .net linq code-analysis reflector


【解决方案1】:

这都是反编译器的问题。下一个代码是通过 DotPeek 反编译 mscorlib 程序集的方法ElementAt 生成的:

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 指令没有while 构造。下面的代码演示了这一点:

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

编译成:

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

【讨论】:

    【解决方案2】:

    我认为是.Net Reflector对代码进行了反编译,原始代码from here没有任何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--;
                    }
                }
            }
    

    【讨论】:

    • JustDecompile 也不会生成 goto。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-13
    • 2015-03-12
    • 2022-07-28
    • 2012-04-11
    • 1970-01-01
    • 2020-10-22
    相关资源
    最近更新 更多