为什么我们不能在 C# 中使用 Iterator StateMachine Attribute?
Why cant we use IteratorStateMachineAttribute in C#?
我在 class 上执行了 Go To Definition (F12) 我试图从中派生,我注意到其中一个方法标有 AsyncStateMachineAttribute
。进而继承 StateMachineAttribute
。我很好奇并决定在 MSDN 上阅读此属性及其所有派生词。这让我想到了 this 并且我遇到了这个声明:
You can't use IteratorStateMachineAttribute
to test whether a method is an iterator method in C#.
因为该声明是为了脱颖而出,所以一定有严重的影响,但没有进一步解释为什么会这样。有没有人有这方面的见解?
这是通知您不能将此标志应用于方法,因为在编译期间它会注入一些无法可靠地添加到方法中的 IL 代码。
我 99% 确定它是历史性的。基本上,C# 在 C# 2 中引入了迭代器块 - 在引入此属性之前 long 时间。
等效的 async 属性是在 C# 中与异步方法同时引入的,所以很好......但即使 C# 编译器现在适用IteratorStateMachineAttribute
到迭代器块:
- 它不适用于使用旧版本编译器创建的库,因此您不能在那里依赖它。
- 它不适用于针对 4.5 之前的 .NET 版本的库。 (老实说,我不确定 VB 编译器在这里做了什么。它可能会省略该属性,或者可能需要您以最新版本的 .NET 为目标才能使用迭代器方法。)
我会说方法上 IteratorStateMachineAttribute
的存在很好地表明它 是 迭代器方法(尽管没有什么可以阻止恶作剧的开发人员将其应用于其他方法),但由于 C# 编译器的旧版本,它不足以进行测试。
这里的State Machine是由C#编译器自动生成的。在继续之前,C# 编译器在内部将许多高级功能(如闭包、yield 关键字和异步)转换为简化的 C#。像 'AsyncStateMachineAttribute' 这样的事情是这样的事情已经发生的一点证据。您可能还熟悉调用的 classes,例如 DisplayClass923084923'1,这是 C# 生成的 classes 以实现闭包。
例如,当您使用 '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' -- 它已被简化为整数和 return 声明。我认为这是 IteratorStateMachineAttribute
添加到 class.
的简化整数和 returns 版本的地方
(我认为 Async 的工作方式相同,生成一个简化的状态机作为其简化步骤,这就是您在文档中得出的结果。)
但是,自从最早的 C# 版本以来,您就拥有了 foreach
关键字,它适用于任何具有 GetEnumerator
方法的对象,并且该枚举器具有 MoveNext
和 Result
。
所以 -- 迭代器方法可能会以不同的方式产生。 IteratorStateMachineAttribute
是编译器在某些情况下提供的内容,但您不应该依赖它。
我在 class 上执行了 Go To Definition (F12) 我试图从中派生,我注意到其中一个方法标有 AsyncStateMachineAttribute
。进而继承 StateMachineAttribute
。我很好奇并决定在 MSDN 上阅读此属性及其所有派生词。这让我想到了 this 并且我遇到了这个声明:
You can't use
IteratorStateMachineAttribute
to test whether a method is an iterator method in C#.
因为该声明是为了脱颖而出,所以一定有严重的影响,但没有进一步解释为什么会这样。有没有人有这方面的见解?
这是通知您不能将此标志应用于方法,因为在编译期间它会注入一些无法可靠地添加到方法中的 IL 代码。
我 99% 确定它是历史性的。基本上,C# 在 C# 2 中引入了迭代器块 - 在引入此属性之前 long 时间。
等效的 async 属性是在 C# 中与异步方法同时引入的,所以很好......但即使 C# 编译器现在适用IteratorStateMachineAttribute
到迭代器块:
- 它不适用于使用旧版本编译器创建的库,因此您不能在那里依赖它。
- 它不适用于针对 4.5 之前的 .NET 版本的库。 (老实说,我不确定 VB 编译器在这里做了什么。它可能会省略该属性,或者可能需要您以最新版本的 .NET 为目标才能使用迭代器方法。)
我会说方法上 IteratorStateMachineAttribute
的存在很好地表明它 是 迭代器方法(尽管没有什么可以阻止恶作剧的开发人员将其应用于其他方法),但由于 C# 编译器的旧版本,它不足以进行测试。
这里的State Machine是由C#编译器自动生成的。在继续之前,C# 编译器在内部将许多高级功能(如闭包、yield 关键字和异步)转换为简化的 C#。像 'AsyncStateMachineAttribute' 这样的事情是这样的事情已经发生的一点证据。您可能还熟悉调用的 classes,例如 DisplayClass923084923'1,这是 C# 生成的 classes 以实现闭包。
例如,当您使用 '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' -- 它已被简化为整数和 return 声明。我认为这是 IteratorStateMachineAttribute
添加到 class.
(我认为 Async 的工作方式相同,生成一个简化的状态机作为其简化步骤,这就是您在文档中得出的结果。)
但是,自从最早的 C# 版本以来,您就拥有了 foreach
关键字,它适用于任何具有 GetEnumerator
方法的对象,并且该枚举器具有 MoveNext
和 Result
。
所以 -- 迭代器方法可能会以不同的方式产生。 IteratorStateMachineAttribute
是编译器在某些情况下提供的内容,但您不应该依赖它。