我正在检查构成Reflector中LINQ扩展的一些代码,这就是我遇到的那种代码:
private bool MoveNext()
{
bool flag;
try
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
this.<set>5__7b = new Set<TSource>(this.comparer);
this.<>7__wrap7d = this.source.GetEnumerator();
this.<>1__state = 1;
goto Label_0092;
case 2:
this.<>1__state = 1;
goto Label_0092;
default:
goto Label_00A5;
}
Label_0050:
this.<element>5__7c = this.<>7__wrap7d.Current;
if (this.<set>5__7b.Add(this.<element>5__7c))
{
this.<>2__current = this.<element>5__7c;
this.<>1__state = 2;
return true;
}
Label_0092:
if (this.<>7__wrap7d.MoveNext())
{
goto Label_0050;
}
this.<>m__Finally7e();
Label_00A5:
flag = false;
}
fault
{
this.System.IDisposable.Dispose();
}
return flag;
}
微软是否有理由以这种方式撰写?
&lt;&gt;也是什么语法意思,如下所示:
switch (this.<>1__state)
我从未见过它在变量之前写过,只有在。
之后答案 0 :(得分:8)
MSIL仍然是有效的2.x代码和&lt;&gt;您看到的名称由C#3.x编译器自动生成。
例如:
public void AttachEvents()
{
_ctl.Click += (sender,e) => MessageBox.Show( "Hello!" );
}
转换为:
public void AttachEvents()
{
_ctl.Click += new EventHandler( <>b_1 );
}
private void <>b_1( object sender, EventArgs e )
{
MessageBox.Show( "Hello!" );
}
我还应该注意,你在Reflector中看到它的原因是你没有打开.NET 3.5优化。转到查看|选项并将优化更改为.NET 3.5,它可以更好地将生成的标识符转换回其lamda表达式。
答案 1 :(得分:7)
当您处理finite state machines时,您会看到C#编译器代表您发出的iterators内部内容。
Jon Skeet在这个主题上有一些很棒的文章(Iterator block implementation details和Iterators, iterator blocks and data pipelines)。另见book的第6章。
此主题有previously个SO帖子。
最后,微软研究院在这个问题上有一个很好的paper。
阅读,直到你满意为止。
答案 2 :(得分:2)
以&lt;&gt;开头的标识符不是有效的C#标识符,所以我怀疑他们使用它们来破坏名称而不用担心冲突,因为C#代码中没有标识符可能是相同的。
至于为何难以阅读,我怀疑这更容易产生。
答案 3 :(得分:2)
这是使用iterators时自动生成的代码。 &lt;&gt;用于确保没有冲突,并且还可以防止您直接在代码中访问编译器生成器类。
有关详细信息,请参阅以下内容:
答案 4 :(得分:2)
这些是编译器从iterator methods自动生成的类型。
编译器将对您自己的迭代器执行完全相同的操作。例如,写下这样的东西,然后看一下Reflector中实际生成的代码:
public IEnumerable<int> GetRandom()
{
Random rng = new Random();
while (true)
{
yield return rng.Next();
}
}
答案 5 :(得分:2)
这是从迭代器自动生成的状态机,如下所示:
static IEnumerable<Func<KeyValuePair<int, int>>> FunnyMethod() {
for (var i = 0; i < 10; i++) {
var localVar = i;
yield return () => new KeyValuePair(localVar, i);
}
}
此方法将为所有值返回10.
编译器将这些方法转换为状态机,将状态存储在<>1__state
字段中,并调用迭代器的每个部分以获得不同的字段值。
<>
部分是生成的字段名称的一部分,选择它是为了不与任何内容冲突。
答案 6 :(得分:0)
你必须了解Reflector的作用。它没有得到源代码。这不是MS的开发人员所写的。 :)它需要中间语言(IL)并系统地将其转换回C#(或VB.NET)。在这样做时,它必须提出一种方法。如你所知,有许多方法可以在代码中对猫进行换肤,最终会产生相同的IL。反射器必须选择一种方法将病房从IL移回到更高级别的语言,并且每次都使用这种方式。
(修正了每条评论,谢谢。)