Gå til indholdet

yield

Brug af yield i C# er en kraftfuld funktion, der tillader udviklere at arbejde med sekvenser af data på en effektiv og nem måde. yield bruges inden i en iterator block til at give en værdi tilbages til den kode, der forbruger iteratoren, hver gang den kaldes, uden at miste staten mellem iterationerne. Dette gør det muligt at skabe komplekse iterationsscenarier, som f.eks. late evaluation (udvurdering efter behov) og stateful iteration, med relativt enkle og læsbare kodekonstruktioner.

Intro til yield

yield er et nøgleord i C#, som bruges til at returnere hvert element et ad gangen fra en iterator metode. En iterator metode er en metode, der returnerer et af to interfaces: IEnumerable eller IEnumerator, afhængigt af om den returnerer en sekvens af værdier eller en enumerator, der kan iterere gennem en sekvens.

For at bruge yield i din C# kode, skal du følge disse trin:

  1. Opret en metode, der returnerer IEnumerable eller IEnumerator. Denne metode vil indeholde din iteration logik.

  2. Brug yield return inde i metoden for at returnere det næste element i sekvensen. Hver gang metoden kaldes af forbrugeren, fortsætter den fra det punkt, hvor den sidst brugte yield return, hvilket gør det muligt at gemme staten mellem iterationerne.

  3. (Valgfrit) Brug yield break for at afslutte iterationen tidligt. Dette er nyttigt, hvis der er en betingelse, der gør, at du ikke ønsker at fortsætte med at returnere elementer.

Eksempel på brug af yield

foreach (int i in GetPowersOfTwoWithoutYield(5))
{
    Console.WriteLine(i);   // *, *, *, *, *, 1, 2, 4, 8, 16
}

foreach (int i in GetPowersOfTwoWithYield(5))
{
    Console.WriteLine(i);   // *, 1, *, 2, *, 4, *, 8, *, 16
}


IEnumerable<int> GetPowersOfTwoWithoutYield(int n)
{
    List<int> result = new List<int>();
    int value = 1;
    for (int i = 0; i < n; i++)
    {
        result.Add(value);
        value = value * 2;
        Console.WriteLine("*");
    }
    return result;
}
IEnumerable<int> GetPowersOfTwoWithYield(int n)
{
    int result = 1;
    for (int i = 0; i < n; i++)
    {
        Console.WriteLine("*");
        yield return result;
        result = result * 2;
    }
}

I dette eksempel returnerer metoderne de første n potenser af 2. Den første metode, GetPowersOfTwoWithoutYield, bruger en List<int> til at gemme resultaterne og returnerer listen, når iterationen er færdig. Den anden metode, GetPowersOfTwoWithYield, bruger yield return til at returnere hvert resultat en ad gangen. Bemærk, at der er en Console.WriteLine("*"); i begge metoder.

Når du kører dette eksempel, vil du se, at GetPowersOfTwoWithoutYield udskriver * fem gange, før den returnerer resultaterne, mens GetPowersOfTwoWithYield udskriver * og returnerer resultaterne en ad gangen. Dette viser, hvordan yield returnerer resultaterne efter behov og gemmer staten mellem iterationerne.

Slutteligt et lidt mere komplekst eksempel med brug af en nedarvet klasse:

class Person
{
    public string Navn { get; set; }
    public int Alder { get; set; }
}

class Personer : IEnumerable<Person>
{
    private List<Person> _personer = new List<Person>();

    public IEnumerator<Person> GetEnumerator()
    {
        return ((IEnumerable<Person>)_personer).GetEnumerator();
    }

    public void TilføjPerson(Person p)
    {
        _personer.Add(p);
    }

    public IEnumerable<Person> FindAllePersoner()
    {
        foreach (var p in _personer)
            yield return p;
    }

    public IEnumerable<Person> FindPersonerUnderAlder(int alder)
    {
        foreach (var p in _personer)
            if (p.Alder < alder)
                yield return p;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable<Person>)_personer).GetEnumerator();
    }
}

Fordele ved at bruge yield

  • Forbedret performance og hukommelsesbrug: Da elementerne genereres efter behov, bruges hukommelsen mere effektivt, og der er ikke behov for at oprette store samlinger op forhånd.
  • Simpel kode for komplekse iterationer: yield gør det nemmere at implementere komplekse iterationsscenarier uden at skulle skrive kompleks kode for at håndtere iterationens tilstand.

Brug af yield i C# er en meget nyttig mekanisme til at arbejde med sekvenser af data på en måde, der er både hukommelseseffektiv og let at kode. Ved at tillade lazy evaluation og simplificere komplekse iterationer, kan yield gøre din kode både mere læsbar og effektiv. Uanset om du arbejder med store datasæt eller komplekse forretningslogikker, kan yield være et værdifuldt værktøj i din C# værktøjskasse.

Opgaver