Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Välj en iterator när du vill returnera en sekvens vars element anropare kan använda en i taget, utan att först skapa det fullständiga resultatet i en samling. Den här metoden passar genererade värden, filter med anpassat kontrollflöde och sekvenser som anropare kan sluta läsa tidigt. Jämfört med en slutförd samling ändras en iterator när arbetet sker, inte bara hur du skriver den.
Tip
I den här artikeln lär du dig synkrona iteratorer för utvecklare som känner till metoder, loopar och samlingar.
yield Fullständig syntax och begränsningar finns i instruktionsreferensenyield.
En iteratormetod genererar en sekvens med värden en i taget. Den här artikeln fokuserar på iteratormetoder som returnerar IEnumerable<T>, vars värden anropare vanligtvis använder med en foreach instruktion.
Skapa element med yield return
Använd yield return för att ange nästa element i sekvensen. Följande iterator väljer godtagbara temperaturavläsningar från en sensor. I det här scenariot -1 markerar slutet på sensordata.
int[] readings = [21, 27, 24, -1, 19];
IEnumerable<int> acceptedReadings =
SelectTemperatures(readings, maximum: 25);
Console.WriteLine("Sequence created.");
foreach (int temperature in acceptedReadings)
{
Console.WriteLine($"Accepted: {temperature}°C");
}
static IEnumerable<int> SelectTemperatures(
IEnumerable<int> readings,
int maximum)
{
foreach (int reading in readings)
{
Console.WriteLine($"Checking {reading}°C");
if (reading == -1)
{
yield break;
}
if (reading <= maximum)
{
yield return reading;
}
}
}
SelectTemperatures returnerar IEnumerable<int>, som representerar en sekvens med int värden. Var och yield return reading en ger ett värde till loopen foreach . När anroparen har hanterat det värdet fortsätter iteratorn med nästa indata.
Använd det allmänna IEnumerable<T> formuläret för den mest moderna C#-koden. Typargumentet, till exempel int, talar om för anropare vilken elementtyp sekvensen innehåller.
Avsluta sekvensen med yield break
Använd yield break för att avsluta en iterator innan kontrollen når slutet av metoden. I exemplet innebär sentinel-värdet -1 att inga fler avläsningar är tillgängliga:
if (reading == -1)
{
yield break;
}
Iteratorn slutar också naturligt när körningen når slutet av kroppen. Använd yield break när ett villkor ska stoppa elementproduktionen omedelbart.
Använda en iterator med foreach
En iterator exponerar samma IEnumerable<T> form som många .NET samlingar. Anropare kan använda foreach utan att veta hur sekvensen genererar dess element:
foreach (int temperature in SelectTemperatures(readings, 25))
{
Console.WriteLine($"Accepted: {temperature}°C");
}
Anroparen begär varje element när loopen utvecklas. Iteratorn behåller sin position mellan begäranden och fortsätter efter föregående yield return.
Förstå produktion av uppskjutna element
Att anropa en iteratormetod kör inte dess brödtext omedelbart. Metoden börjar producera element när anroparen börjar räkna upp. Det här beteendet kallas uppskjuten körning.
Exemplet skrivs Sequence created. ut före eventuella Checking ... meddelanden. Iteratorn börjar bara kontrollera avläsningar när loopen foreach frågar efter sitt första element.
Uppskjuten körning har praktiska effekter:
- Anroparen kan börja bearbeta innan iteratorn skapar varje element.
- Iteratorn kan sluta tidigt med
yield break. - En anropare som aldrig räknar upp sekvensen kör inte iteratortexten.
- Varje ny uppräkning kör iteratorn igen.
Gör uppskjuten körning tydlig i metodens syfte och dokumentation. Läsare kan inte härleda körningstidsinställningar från IEnumerable<T> en och samma plats eftersom både iteratorer och samlingar kan exponera gränssnittet. Håll elementproduktionen fri från orelaterade biverkningar eftersom anropare kan räkna upp sekvensen senare eller mer än en gång. Exemplets diagnostikmeddelanden illustrerar den tidpunkten.
Välj en iterator eller samling
Returnera en iterator när värden naturligt anländer en i taget eller när anroparen inte behöver det fullständiga resultatet omedelbart. Returnera en slutförd samling när anropare behöver en stabil ögonblicksbild, indexerad åtkomst eller upprepad uppräkning utan att räkna om elementen.
Båda metoderna kan returnera samma element. Iteratorn lämnar elementproduktionen under anroparens kontroll. en metod som skapar en samling slutförs som fungerar innan den returneras.
Använd en vanlig loop när du vill utföra en åtgärd för varje objekt utan att returnera en sekvens. För ett standardfilter eller en standardtransformering föredrar du en LINQ-åtgärd som Where eller Select; skriver en iterator när logiken för anpassad elementproduktion är tydligare som en serie instruktioner.
Iteratormetoderna består av LINQ eftersom båda använder IEnumerable<T>. En anropare kan till exempel lägga till ett annat filter:
var comfortableReadings = SelectTemperatures(readings, 25)
.Where(static temperature => temperature >= 18);
Iteratorn och LINQ-åtgärden förblir uppskjutna tills koden räknas comfortableReadingsupp .
Asynkrona sekvenser finns i Generera och använda asynkrona strömmar. Använd språkreferensen för anpassade uppräkningsmönster och alla yield begränsningar.