Heim Backend-Entwicklung C#.Net-Tutorial C# 2.0-Spezifikation (Iterator) (2)

C# 2.0-Spezifikation (Iterator) (2)

Jan 03, 2017 pm 01:04 PM

22.4 yield-Anweisung

Die yield-Anweisung wird in einem Iteratorblock verwendet, um einen Enumeratorobjektwert zu erzeugen oder das Ende der Iteration anzuzeigen.
embedded-statement: (eingebettete Anweisung)
...
Yield-Statement (Yield-Anweisung)
Yield-Statement: (Yield-Anweisung)
Yield Return Expression ;
Yield Break ;
Um die Kompatibilität mit vorhandenen Programmen sicherzustellen, ist yield kein reserviertes Wort und yield hat nur unmittelbar vor den Schlüsselwörtern return oder break eine besondere Bedeutung. In anderen Kontexten kann es als Identifikator verwendet werden. Es gibt verschiedene Einschränkungen, wo die
Renditeabrechnung erscheinen kann, wie unten beschrieben.
l Wenn die Yield-Anweisung außerhalb des Methodenkörpers, des Operatorkörpers und des Zugriffskörpers erscheint, führt dies zu einem Fehler bei der Kompilierung.
l Wenn die yield-Anweisung in einer anonymen Methode erscheint, führt dies zu einem Fehler bei der Kompilierung.
l Wenn die yield-Anweisung in der final-Anweisung der try-Anweisung erscheint, führt dies zu einem Fehler bei der Kompilierung.
l Die yield return-Anweisung verursacht einen Fehler bei der Kompilierung, wenn sie irgendwo in einer try-Anweisung erscheint, die eine Catch-Unteranweisung enthält.
Die folgenden Beispiele zeigen einige gültige und ungültige Verwendungen der Yield-Anweisung.

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; // 错误, 迭代器块的错误返回类型
}
Nach dem Login kopieren

Es muss eine implizite Konvertierung (§6.1) vom Ausdruckstyp in der Yield-Return-Anweisung zum Yield-Typ des Iterators (§22.1.3) erfolgen.
Die Yield-Return-Anweisung wird wie folgt ausgeführt.
l Der in der Anweisung angegebene Ausdruck wird ausgewertet (ausgewertet), implizit in den generierten Typ konvertiert und der Current-Eigenschaft des Enumeratorobjekts zugewiesen.
l Die Ausführung des Iteratorblocks wird ausgesetzt. Wenn sich die Yield-Return-Anweisung in einem oder mehreren Try-Blöcken befindet, wird der zugehörige Final-Block zu diesem Zeitpunkt nicht ausgeführt.
l Die MoveNext-Methode des Enumeratorobjekts gibt „true“ an den Aufrufer zurück, was angibt, dass das Enumeratorobjekt erfolgreich zum nächsten Element übergeht.

Der nächste Aufruf der MoveNext-Methode des Enumeratorobjekts setzt die Ausführung an der Stelle fort, an der der Iteratorblock angehalten wurde.
Die Yield Break-Anweisung wird wie folgt ausgeführt.
l Wenn die Yield Break-Anweisung in einem oder mehreren Try-Blöcken mit Final-Blöcken enthalten ist, wird die anfängliche Kontrolle an den Final-Block der innersten Try-Anweisung übertragen. Wenn die Steuerung den Endpunkt des „final“-Blocks erreicht, wird die Steuerung an den „final“-Block der nächstgelegenen try-Anweisung übertragen. Dieser Vorgang wird wiederholt, bis alle inneren „finally“-Blöcke der try-Anweisungen ausgeführt wurden.
l Die Kontrolle wird an den Aufrufer des Iteratorblocks zurückgegeben. Dies kann an der MoveNext-Methode oder der Dispose-Methode des Enumeratorobjekts liegen.

Da die Yield-Break-Anweisung die Kontrolle bedingungslos an eine andere Stelle überträgt, wird der Endpunkt der Yield-Break-Anweisung niemals erreicht.

22.4.1 Explizite Zuweisung

Für die Yield Return Statement stmt in Form von Yield Return expr

l Wie der Anfang von stmt, am Anfang von expr Die Variable v hat den Status „Explizite Zuweisung“.
l Wenn v explizit am Endpunkt von expr zugewiesen wird, wird es auch explizit am Endpunkt von stmt zugewiesen; andernfalls wird es nicht explizit am Endpunkt von stmt zugewiesen

22.5 Implementierungsbeispiel

In diesem Abschnitt werden mögliche Implementierungen von Iteratoren in Form von Standard-C#-Konstrukten beschrieben. Die hier beschriebene Implementierung basiert auf den gleichen Prinzipien wie der Microsoft C#-Compiler, ist jedoch keineswegs die zwingende oder einzig mögliche Implementierung.
Die folgende Stack-Klasse implementiert die GetEnumerator-Methode mithilfe von Iteratoren. Dieser Iterator zählt die Elemente des Stapels in der Reihenfolge von oben nach unten auf.

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];
}
}
Nach dem Login kopieren

Die GetEnumerator-Methode kann in eine Instanz der vom Compiler generierten Enumeratorklasse konvertiert werden, die den Code im Iteratorblock kapselt, wie unten gezeigt.

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();
}
}
Nach dem Login kopieren

In der vorherigen Transformation wurde der Code im Iteratorblock in eine Zustandsmaschine konvertiert und in der MoveNext-Methode der Enumeratorklasse platziert. Darüber hinaus wird die lokale Variable i in ein Feld des Enumeratorobjekts konvertiert, sodass sie während des Aufrufs von MoveNext bestehen bleiben kann.
Das folgende Beispiel druckt eine einfache Multiplikationstabelle mit den ganzen Zahlen 1 bis 10. In diesem Beispiel gibt die FromTo-Methode ein aufzählbares Objekt zurück und wird mithilfe eines Iterators implementiert.

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();
}
}
}
Nach dem Login kopieren

Die FromTo-Methode kann in eine Instanz einer vom Compiler generierten aufzählbaren Klasse konvertiert werden, die den Code in einem Iteratorblock kapselt, wie unten gezeigt.

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();
}
}
}
Nach dem Login kopieren

这个可枚举类实现了可枚举接口和枚举器接口,这使得它成为可枚举的或枚举器。当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)!


Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

Video Face Swap

Video Face Swap

Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Wie man verschiedene Symbole in der C -Sprache verwendet Wie man verschiedene Symbole in der C -Sprache verwendet Apr 03, 2025 pm 04:48 PM

Die Nutzungsmethoden von Symbolen in der C-Sprachabdeckung Arithmetik, Zuordnung, Bedingungen, Logik, Bitoperatoren usw. werden für grundlegende mathematische Operationen verwendet, Zuordnungsoperatoren werden zur Zuordnung und Addition verwendet, Subtraktion, Multiplikationszuordnung und Abteilungszuweisung, Zustandsbetreiber werden für Unterschiede verwendet. Logische Operationen werden verwendet. Logische Operationen werden verwendet. Logische Operationen werden verwendet. Zeiger, Markierungen am Ende der Datei und nicht numerische Werte.

Was ist die Rolle von CHAR in C -Saiten? Was ist die Rolle von CHAR in C -Saiten? Apr 03, 2025 pm 03:15 PM

In C wird der Zeichenentyp in Saiten verwendet: 1. Speichern Sie ein einzelnes Zeichen; 2. Verwenden Sie ein Array, um eine Zeichenfolge darzustellen und mit einem Null -Terminator zu enden. 3. Durch eine Saitenbetriebsfunktion arbeiten; 4. Lesen oder geben Sie eine Zeichenfolge von der Tastatur aus.

Wie man mit Sonderfiguren in der C -Sprache umgeht Wie man mit Sonderfiguren in der C -Sprache umgeht Apr 03, 2025 pm 03:18 PM

In der C -Sprache werden Sonderzeichen durch Escape -Sequenzen verarbeitet, wie z. B.: \ n repräsentiert Linienbrüche. \ t bedeutet tab charakter. Verwenden Sie Escape -Sequenzen oder Zeichenkonstanten, um Sonderzeichen darzustellen, wie z. B. char c = '\ n'. Beachten Sie, dass der Backslash zweimal entkommen muss. Verschiedene Plattformen und Compiler haben möglicherweise unterschiedliche Fluchtsequenzen. Bitte wenden Sie sich an die Dokumentation.

Der Unterschied zwischen char und wchar_t in der C -Sprache Der Unterschied zwischen char und wchar_t in der C -Sprache Apr 03, 2025 pm 03:09 PM

In der C -Sprache ist der Hauptunterschied zwischen char und wchar_t die Zeichencodierung: char verwendet ASCII oder erweitert ASCII, wchar_t Unicode; char nimmt 1-2 Bytes auf, wchar_t nimmt 2-4 Bytes auf; char ist für englischen Text geeignet. Wchar_t ist für mehrsprachige Text geeignet. char ist weithin unterstützt, wchar_t hängt davon ab, ob der Compiler und das Betriebssystem Unicode unterstützen. char ist in der Charakterbereich begrenzt, WCHAR_T hat einen größeren Charakterbereich und spezielle Funktionen werden für arithmetische Operationen verwendet.

Der Unterschied zwischen Multithreading und asynchronem C# Der Unterschied zwischen Multithreading und asynchronem C# Apr 03, 2025 pm 02:57 PM

Der Unterschied zwischen Multithreading und Asynchron besteht darin, dass Multithreading gleichzeitig mehrere Threads ausführt, während asynchron Operationen ausführt, ohne den aktuellen Thread zu blockieren. Multithreading wird für rechenintensive Aufgaben verwendet, während asynchron für die Benutzerinteraktion verwendet wird. Der Vorteil des Multi-Threading besteht darin, die Rechenleistung zu verbessern, während der Vorteil von Asynchron nicht darin besteht, UI-Threads zu blockieren. Die Auswahl von Multithreading oder Asynchron ist von der Art der Aufgabe abhängt: Berechnungsintensive Aufgaben verwenden Multithreading, Aufgaben, die mit externen Ressourcen interagieren und die UI-Reaktionsfähigkeit asynchron verwenden müssen.

Wie man CHO in C -Sprache umwandelt Wie man CHO in C -Sprache umwandelt Apr 03, 2025 pm 03:21 PM

In der C -Sprache kann die char -Typ -Konvertierung direkt in einen anderen Typ konvertiert werden, wenn: Casting: Verwenden von Casting -Zeichen. Automatische Konvertierung des Typs: Wenn ein Datentyp einen anderen Werttyp berücksichtigen kann, wandelt der Compiler diese automatisch um.

Was ist die Funktion der C -Sprachsumme? Was ist die Funktion der C -Sprachsumme? Apr 03, 2025 pm 02:21 PM

Es gibt keine integrierte Summenfunktion in der C-Sprache, daher muss sie selbst geschrieben werden. Die Summe kann erreicht werden, indem das Array durchquert und Elemente akkumulieren: Schleifenversion: Die Summe wird für die Schleifen- und Arraylänge berechnet. Zeigerversion: Verwenden Sie Zeiger, um auf Array-Elemente zu verweisen, und eine effiziente Summierung wird durch Selbststillstandszeiger erzielt. Dynamisch Array -Array -Version zuweisen: Zuordnen Sie Arrays dynamisch und verwalten Sie selbst den Speicher selbst, um sicherzustellen, dass der zugewiesene Speicher befreit wird, um Speicherlecks zu verhindern.

So verwenden Sie char Array in C -Sprache So verwenden Sie char Array in C -Sprache Apr 03, 2025 pm 03:24 PM

Das Char -Array speichert Zeichensequenzen in der C -Sprache und wird als char Array_name [Größe] deklariert. Das Zugriffselement wird durch den Einweisoperator weitergeleitet, und das Element endet mit dem Null -Terminator '\ 0', der den Endpunkt der Zeichenfolge darstellt. Die C -Sprache bietet eine Vielzahl von String -Manipulationsfunktionen wie Strlen (), Strcpy (), Strcat () und strcmp ().

See all articles