我对一个试图派生的类执行了Go To Definition(F12),并注意到其中一个方法标记有AsyncStateMachineAttribute
。它又继承了CCD_ 2。我很好奇,决定在MSDN上阅读这个属性及其所有派生属性。这让我想到了这一点,我发现了这样一句话:
在C#中,不能使用
IteratorStateMachineAttribute
来测试一个方法是否是迭代器方法。
因为这句话是为了突出,所以肯定会有严重的影响,但没有进一步的解释为什么会这样。有人在这方面有见解吗?
我敢肯定这是历史性的。基本上,C#在C#2中引入了迭代器块——在引入该属性之前,这是一个长的时间。
等价的async属性是在C#中与async方法同时引入的,所以这很好。。。但是即使C#编译器现在将IteratorStateMachineAttribute
应用于迭代器块:
- 它不适用于使用旧版本编译器创建的库,因此您无法在那里依赖它
- 它不能应用于针对.NET 4.5之前版本的库。(老实说,我不确定VB编译器在这里做了什么。它可能省略了属性,也可能要求您针对最新版本的.NET才能使用迭代器方法。)
我想说,一个方法上IteratorStateMachineAttribute
的存在很好地表明它是迭代器方法(尽管没有什么可以阻止恶意开发人员将其应用于其他方法),但由于C#编译器的旧版本,这不是一个充分的测试。
这里的状态机是由C#编译器自动生成的。在继续之前,C#编译器在内部将许多高级特性(如闭包、yield关键字和async)转换为简化的C#。像"AsyncStateMachineAttribute"这样的东西就是这样的事情发生的一个证据。您可能还熟悉名为DisplayClass923084923'1的类,这些类是C#为实现闭包而生成的类。
当你使用"yield"时,比如说,C#编译器首先生成一个不使用"yielt"而是使用状态机实现的代码版本。原则上,由此;
yield "A";
yield "B";
至
int _state = 0;
if (_state == 0) { state = 1; return "A"; }
if (_state == 1) { state = 2; return "B"; }
这意味着C#编译器以后不必像那样处理"yield">——它被简化为整数和返回语句。我认为这就是IteratorStateMachineAttribute
被添加到类的简化、int和return版本中的地方。
(我认为Async的工作方式是一样的,生成一个简化的状态机作为其简化步骤,这就是您在文档中使用它的方式。)
然而,从C#的最早版本开始,您就有了foreach
关键字,它适用于任何具有GetEnumerator
方法的对象,并且该枚举器具有MoveNext
和Result
等方法。
因此,迭代器方法可能会以不同的方式产生。IteratorStateMachineAttribute
在某些情况下是由编译器提供的,但您不应该依赖它。
这是通知您不能将此标志应用于方法,因为在编译过程中,它将注入一些无法可靠添加到方法中的IL代码。