【发布时间】:2020-02-03 09:55:10
【问题描述】:
我试图了解迭代器在内部是如何工作的,以减轻我对线程安全的一些担忧。让我们考虑例如以下 简单的迭代器:
using System.Collections.Generic;
public class MyClass
{
public static IEnumerable<int> MyMethod()
{
yield return 10;
yield return 20;
yield return 30;
}
}
在将此代码复制粘贴到SharpLab.io 之后,我可以看到在后台创建的编译器生成的状态机。它是一个实现接口IEnumerable<int>和IEnumerator<int>的类,并包含下面的MoveNext方法:
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = 10;
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
<>2__current = 20;
<>1__state = 2;
return true;
case 2:
<>1__state = -1;
<>2__current = 30;
<>1__state = 3;
return true;
case 3:
<>1__state = -1;
return false;
}
}
标识符<>1__state 和<>2__current 是此类的私有字段:
private int <>1__state;
private int <>2__current;
我注意到这段代码中有一个模式。首先将<>1__state 字段的值恢复为-1,然后将<>2__current 分配给下一个迭代值,然后将<>1__state 推进到下一个状态。我的问题是:<>1__state = -1; 行的目的是什么?我编译了这段代码(在痛苦地重命名所有非法标识符之后)并确认可以注释掉这一行而不影响类的功能。我不相信 C# 编译器团队只是忘记了这段看似毫无目的的代码。它的存在肯定是有目的的,我想知道这个目的是什么。
【问题讨论】:
-
这里的
<>是什么? -
@OlivierRogier 这是一个似乎对编译器生成的代码有效的前缀。根据 C# 规范肯定是无效的,所以我不得不重命名变量来编译这段代码。
-
我不明白,因为
<>是菱形运算符:它允许对开放类型进行真正的泛型多态性,据我所知,它在 C# 中尚不可用。 -
@OlivierRogier 我认为尖括号在这里没有任何意义。添加可能是为了使标识符无效,以避免与用户代码冲突。
-
this.__state = -1;的用途相当简单。这就是状态机的工作原理。因为状态机不知道您请求什么值,并且您的用户代码可能是一个非常慢的 Web 服务请求,所以它将状态设置为 -1 表示“我正忙于获取下一个值”。
标签: c# compilation iterator state-machine