C# 2.0 Specification(迭代器)(二)
22.4 yield 语句
yield语句用于迭代器块以产生一个枚举器对象值,或表明迭代的结束。
embedded-statement:(嵌入语句)
...
yield-statement(yield语句)
yield-statement:(yield 语句)
yield return expression ;
yield break ;
为了确保和现存程序的兼容性,yield并不是一个保留字,并且 yield只有在紧邻return或break关键词之前才具有特别的意义。而在其他上下文中,它可以被用作标识符。
yield语句所能出现的地方有几个限制,如下所述。
l yield语句出现在方法体、运算符体和访问器体之外时,将导致编译时错误。
l yield语句出现在匿名方法之内时,将导致编译时错误。
l yield语句出现在try语句的finally语句中时,将导致编译时错误。
l yield return 语句出现在包含catch子语句的任何try语句中任何位置时,将导致编译时错误。
如下示例展示了yield语句的一些有效和无效用法。
delegate IEnumerable<int> D(); IEnumerator<int> GetEnumerator() { try { yield return 1; // Ok yield break; // Ok } finally { yield return 2; // 错误, yield 在finally中 yield break; // 错误, yield 在 finally中 } try { yield return 3; // 错误, yield return 在try...catch中 yield break; // Ok } catch { yield return 4; // 错误, yield return 在 try...catch中 yield break; // Ok } D d = delegate { yield return 5; // 错误, yield 在匿名方法中 }; } int MyMethod() { yield return 1; // 错误, 迭代器块的错误返回类型 }
从yield return 语句中表达式类型到迭代器的产生类型(§22.1.3),必须存在隐式转换(§6.1)。
yield return 语句按如下方式执行。
l 在语句中给出的表达式将被计算(evaluate),隐式地转换到产生类型,并被赋给枚举器对象的Current属性。
l 迭代器块的执行将被挂起。如果yield return 语句在一个或多个try块中,与之关联的finally块此时将不会执行。
l 枚举器对象的MoveNext方法对调用方返回true,表明枚举器对象成功前进到下一个项。
对枚举器对象的MoveNext方法的下一次调用,重新从迭代器块挂起的地方开始执行。
yeld break 语句按如下方式执行。
l 如果yield break 语句被包含在一个或多个带有finally块的try块内,初始控制权将转移到最里面的try语句的finally块。当控制到达finally块的结束点后,控制将会转移到下一个最近的try语句的finally块。这个过程将会一直重复直到所有内部的try语句的finally块都被执行。
l 控制返回到迭代器块的调用方。这可能是由于枚举器对象的MoveNext方法或Dispose方法。
由于yield break语句无条件的转移控制到别处,所以yield break语句的结束点将永远不能到达。
22.4.1明确赋值
对于以yield return expr 形式的yield return 语句stmt
l 像stmt开始一样,在expr的开头变量v具有明确的赋值状态。
l 如果在expr的结束点v被明确赋值,那它在stmt的结束点也将被明确赋值;否则,在stmt结束点将不会被明确赋值
22.5实现例子
本节以标准C#构件的形式描述了迭代器的可能实现。此处描述的实现基于与Microsoft C#编译器相同的原则,但这绝不是强制或唯一可能的实现。
如下Stack
using System; using System.Collections; using System.Collections.Generic; class Stack<T>: IEnumerable<T> { T[] items; int count; public void Push(T item) { if (items == null) { items = new T[4]; } else if (items.Length == count) { T[] newItems = new T[count * 2]; Array.Copy(items, 0, newItems, 0, count); items = newItems; } items[count++] = item; } public T Pop() { T result = items[--count]; items[count] = T.default; return result; } public IEnumerator<T> GetEnumerator() { for (int i = count - 1; i >= 0; --i) yield items[i]; } }
GetEnumerator方法可以被转换到编译器生成的枚举器类的实例,该类封装了迭代器块中的代码,如下所示。
class Stack<T>: IEnumerable<T> { ... public IEnumerator<T> GetEnumerator() { return new __Enumerator1(this); } class __Enumerator1: IEnumerator<T>, IEnumerator { int __state; T __current; Stack<T> __this; int i; public __Enumerator1(Stack<T> __this) { this.__this = __this; } public T Current { get { return __current; } } object IEnumerator.Current { get { return __current; } } public bool MoveNext() { switch (__state) { case 1: goto __state1; case 2: goto __state2; } i = __this.count - 1; __loop: if (i < 0) goto __state2; __current = __this.items[i]; __state = 1; return true; __state1: --i; goto __loop; __state2: __state = 2; return false; } public void Dispose() { __state = 2; } void IEnumerator.Reset() { throw new NotSupportedException(); } }
在先前的转换中,迭代器块之内的代码被转换成state machine,并被放置在枚举器类的MoveNext方法中。此外局部变量i被转换成枚举器对象的一个字段,因此在MoveNext的调用过程中可以持续存在。
下面的例子打印一个简单的从整数1到10的乘法表。该例子中FromTo方法返回一个可枚举对象,并且使用迭代器实现。
using System; using System.Collections.Generic; class Test { static IEnumerable<int> FromTo(int from, int to) { while (from <= to) yield return from++; } static void Main() { IEnumerable<int> e = FromTo(1, 10); foreach (int x in e) { foreach (int y in e) { Console.Write("{0,3} ", x * y); } Console.WriteLine(); } } }
FromTo方法可被转换成编译器生成的可枚举类的实例,该类封装了迭代器块中的代码,如下所示。
using System; using System.Threading; using System.Collections; using System.Collections.Generic; class Test { ... static IEnumerable<int> FromTo(int from, int to) { return new __Enumerable1(from, to); } class __Enumerable1: IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator { int __state; int __current; int __from; int from; int to; int i; public __Enumerable1(int __from, int to) { this.__from = __from; this.to = to; } public IEnumerator<int> GetEnumerator() { __Enumerable1 result = this; if (Interlocked.CompareExchange(ref __state, 1, 0) != 0) { result = new __Enumerable1(__from, to); result.__state = 1; } result.from = result.__from; return result; } IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } public int Current { get { return __current; } } object IEnumerator.Current { get { return __current; } } public bool MoveNext() { switch (__state) { case 1: if (from > to) goto case 2; __current = from++; __state = 1; return true; case 2: __state = 2; return false; default: throw new InvalidOperationException(); } } public void Dispose() { __state = 2; } void IEnumerator.Reset() { throw new NotSupportedException(); } } }
这个可枚举类实现了可枚举接口和枚举器接口,这使得它成为可枚举的或枚举器。当GetEnumerator方法被首次调用时,将返回可枚举对象自身。后续可枚举对象的GetEnumerator调用,如果有的话,都返回可枚举对象的拷贝。因此,每次返回的枚举器都有其自身的状态,改变一个枚举器将不会影响另一个。Interlocked.CompareExchange方法用于确保线程安全操作。
from和to参数被转换为可枚举类的字段。由于from在迭代器块内被修改,所以引入另一个__from字段来保存在每个枚举其中from的初始值。
如果当__state是0时MoveNext被调用,该方法将抛出InvalidOperationException异常。这将防止没有首次调用GetEnumerator,而将可枚举对象作为枚举器而使用的现象发生。
(C# 2.0 Specification 全文完)
以上就是C# 2.0 Specification(迭代器)(二)的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Les méthodes d'utilisation des symboles dans la couverture du langage C Couverture arithmétique, l'affectation, les conditions, la logique, les opérateurs de bits, etc. Les opérateurs arithmétiques sont utilisés pour les opérations mathématiques de base, les opérateurs d'affectation sont utilisés pour les opérations et les opérations de la soustraction, la multiplication et les opérations de division, les opérations BIT sont utilisé pointeurs nuls, marqueurs de fin de fichier et valeurs non nucères.

En C, le type de char est utilisé dans les chaînes: 1. Stockez un seul caractère; 2. Utilisez un tableau pour représenter une chaîne et se terminer avec un terminateur nul; 3. Faire fonctionner via une fonction de fonctionnement de chaîne; 4. Lisez ou sortant une chaîne du clavier.

Dans le langage C, les caractères spéciaux sont traités à travers des séquences d'échappement, telles que: \ n représente les pauses de ligne. \ t signifie le caractère d'onglet. Utilisez des séquences d'échappement ou des constantes de caractères pour représenter des caractères spéciaux, tels que char c = '\ n'. Notez que l'arrière-plan doit être échappé deux fois. Différentes plates-formes et compilateurs peuvent avoir différentes séquences d'échappement, veuillez consulter la documentation.

Dans le langage C, la principale différence entre Char et WCHAR_T est le codage des caractères: Char utilise ASCII ou étend ASCII, WCHAR_T utilise Unicode; Char prend 1 à 2 octets, WCHAR_T occupe 2-4 octets; Char convient au texte anglais, WCHAR_T convient au texte multilingue; Le char est largement pris en charge, WCHAR_T dépend de la prise en charge du compilateur et du système d'exploitation Unicode; Le char est limité dans la gamme de caractères, WCHAR_T a une gamme de caractères plus grande et des fonctions spéciales sont utilisées pour les opérations arithmétiques.

La différence entre le multithreading et l'asynchrone est que le multithreading exécute plusieurs threads en même temps, tandis que les opérations effectuent de manière asynchrone sans bloquer le thread actuel. Le multithreading est utilisé pour les tâches à forte intensité de calcul, tandis que de manière asynchrone est utilisée pour l'interaction utilisateur. L'avantage du multi-threading est d'améliorer les performances informatiques, tandis que l'avantage des asynchrones est de ne pas bloquer les threads d'interface utilisateur. Le choix du multithreading ou asynchrone dépend de la nature de la tâche: les tâches à forte intensité de calcul utilisent le multithreading, les tâches qui interagissent avec les ressources externes et doivent maintenir la réactivité de l'interface utilisateur à utiliser asynchrone.

Dans le langage C, la conversion de type char peut être directement convertie en un autre type par: Casting: Utilisation de caractères de casting. Conversion de type automatique: Lorsqu'un type de données peut accueillir un autre type de valeur, le compilateur le convertit automatiquement.

Il n'y a pas de fonction de somme intégrée dans le langage C, il doit donc être écrit par vous-même. La somme peut être obtenue en traversant le tableau et en accumulant des éléments: Version de boucle: la somme est calculée à l'aide de la longueur de boucle et du tableau. Version du pointeur: Utilisez des pointeurs pour pointer des éléments de tableau, et un résumé efficace est réalisé grâce à des pointeurs d'auto-incitation. Allouer dynamiquement la version du tableau: allouer dynamiquement les tableaux et gérer la mémoire vous-même, en veillant à ce que la mémoire allouée soit libérée pour empêcher les fuites de mémoire.

Le Array Char stocke des séquences de caractères en C et est déclaré Char Array_name [Taille]. L'élément d'accès est passé par l'opérateur d'indice, et l'élément se termine par le terminateur nul «\ 0», qui représente le point final de la chaîne. Le langage C fournit une variété de fonctions de manipulation de cordes, telles que strlen (), strcpy (), strcat () et strcmp ().
