我认为这是一个真命题:“没有用.NET Reflector反编译并阅读过代码的程序员不是专业的.NET程序 员”。.NET Reflector强大的地方就在于可以把IL代码反编译成可读性颇高的高级语言代码,并且能够支 持相当多的“模式”,根据这些模式它可以在一定程度上把某些语法糖给还原,甚至可以支持简单的 Lambda表达式和LINQ。只可惜,.NET Reflector还是无法做到极致,某些情况下生成的代码还是无法还原 到易于理解——yield关键字便是这样一个典型的情况。不过还行,对于不复杂的逻辑,我们可以通过人 肉来“整理”个大概。
简单yield方法编译结果分析
yeild的作用是简化枚举器,也就是IEnumerator<T>或IEnumerable<T>的实现。“人肉” 反编译的关键在于发现编译器的规律,因此我们先来观察编译器的处理结果。值得注意的是,我们这里所 谈的“分析”,都采用的是微软目前的C# 3.0编译器。从理论上来说,这些结果或是规律,都有可能无法 运用在Mono和微软之前或今后的C#编译器上。首先我们准备一段使用yield的代码:
static IEnumerator<int> GetSimpleEnumerator()
{
Console.WriteLine("Creating Enumerator");
yield return 0;
yield return 1;
yield return 2;
Console.WriteLine("Enumerator Created");
}
为了简化问题,我们在这里采用IEnumerator<T>。自动生成的IEnumerable<T>和 IEnumerator<T>区别不大,您可以自己观察一下,有机会我会单独讨论和分析其中的区别。经过编 译之后再使用.NET Reflector进行反编译,得到的结果是:
private static IEnumerator<int> GetSimpleEnumerator()
{
return new <GetSimpleEnumerator>d__0(0);
}
[CompilerGenerated]
private sealed class <GetSimpleEnumerator>d__0 : IEnumerator<int>, ...
{
// Fields
private int <>1__state;
private int <>2__current;
// Methods
[DebuggerHidden]
public <GetSimpleEnumerator>d__0(int <>1__state)
{
this.<>1__state = <>1__state;
}
private bool MoveNext()
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
Console.WriteLine("Creating Enumerator");
this.<>2__current = 0;
this.<>1__state = 1;
return true;
case 1:
this.<>1__state = -1;
this.<>2__current = 1;
this.<>1__state = 2;
return true;
case 2:
this.<>1__state = -1;
this.<>2__current = 2;
this.<>1__state = 3;
return true;
case 3:
this.<>1__state = -1;
Console.WriteLine("Enumerator Created");
break;
}
return false;
}
...
}