【问题标题】:Why cant we use IteratorStateMachineAttribute in C#?为什么我们不能在 C# 中使用 Iterator StateMachine 属性?
【发布时间】:2016-09-20 02:42:53
【问题描述】:

我在尝试派生的类上执行了转到定义 (F12),我注意到其中一个方法标有 AsyncStateMachineAttribute。这又继承了StateMachineAttribute。我很好奇并决定在 MSDN 上阅读此属性及其所有派生词。这让我找到了this,我看到了这个声明:

您不能使用IteratorStateMachineAttribute 来测试一个方法是否是 C# 中的迭代器方法。

因为该声明是为了突出,所以它肯定有严重的影响,但没有进一步解释为什么会这样。有没有人有这方面的见解?

【问题讨论】:

  • 我认为这只是想说您不能依靠属性在反射上下文中测试此类方法(例如通过静态分析器)。跨度>
  • 它高度特定于 VB.NET。将元数据转换回 VB.NET 声明的工具(如 Go To Definition)使用它来知道需要使用 Iterator 关键字显示函数。如果没有这些帮助,Iterator Function() As T 将显示为 Function() As IEnumerable(Of T)。 C# 编译器现在也发出它,在 VB.NET 在 VS2012 中获得迭代器支持之前它没有这样做。所以你不能依赖它。

标签: c# iterator state-machine compiler-services


【解决方案1】:

这表明您不能将此标志应用于方法,因为在编译期间它会注入一些不能可靠地添加到方法中的 IL 代码。

【讨论】:

    【解决方案2】:

    我 99% 确定这是历史性的。基本上,C# 在 C# 2 中引入了迭代器块 - 在引入此属性之前 很长 时间。

    等效的 async 属性是与 C# 中的异步方法同时引入的,所以这很好......但即使 C# 编译器 现在IteratorStateMachineAttribute 应用于迭代器块:

    • 它不适用于使用旧版本编译器创建的库,因此您无法依赖它。
    • 它不适用于面向 .NET 4.5 之前版本的库。 (老实说,我不确定 VB 编译器在这里做了什么。它可能会省略该属性,或者可能需要您针对最新版本的 .NET 才能使用迭代器方法。)

    我会说,方法上存在IteratorStateMachineAttribute 很好地表明它是一个迭代器方法(尽管没有什么可以阻止调皮的开发人员将其应用于其他方法),但由于 C# 编译器版本较旧,因此测试不够充分。

    【讨论】:

      【解决方案3】:

      这里的状态机是由 C# 编译器自动生成的。 C# 编译器在继续之前在内部将许多高级特性(如闭包、yield 关键字和异步)转换为简化的 C#。诸如“AsyncStateMachineAttribute”之类的事情是发生此类事情的一点证据。您可能还熟悉名为 DisplayClass923084923'1 的类,它们是 C# 为实现闭包而生成的类。

      比如说,当您使用“yield”时,C# 编译器首先会生成一个不使用“yield”而是使用状态机实现的代码版本。原则上,由此而来;

      yield "A";
      yield "B";
      

      int _state = 0;
      
      if (_state == 0) { state = 1; return "A"; }
      if (_state == 1) { state = 2; return "B"; }
      

      这意味着 C# 编译器稍后不必处理“yield”——它已被简化为整数和返回语句。我认为这是将IteratorStateMachineAttribute 添加到该类的简化的整数和返回版本的地方。

      (我认为 Async 的工作方式相同,生成一个简化的状态机作为其简化步骤,这就是您在文档中的方式。)

      但是,从最早的 C# 版本开始,您就拥有了 foreach 关键字,该关键字适用于具有 GetEnumerator 方法的任何对象,并且该枚举器具有像 MoveNextResult 这样的方法。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-20
        • 1970-01-01
        相关资源
        最近更新 更多