为什么我们不能在C#中使用IteratorStateMachineAttribute



我对一个试图派生的类执行了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方法的对象,并且该枚举器具有MoveNextResult等方法。

因此,迭代器方法可能会以不同的方式产生。IteratorStateMachineAttribute在某些情况下是由编译器提供的,但您不应该依赖它。

这是通知您不能将此标志应用于方法,因为在编译过程中,它将注入一些无法可靠添加到方法中的IL代码。

相关内容

  • 没有找到相关文章

最新更新