我正在查看Linq扩展方法.NET Reflector的ElementAt生成的一些代码,我看到了这段代码:
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);
}
答案 0 :(得分:4)
我认为它的.Net Reflector已反编译代码,原始代码from here没有任何转到
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--;
}
}
}
答案 1 :(得分:4)
这都是反编译器的问题。下一个代码是通过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