Frage Richtige Verwendung von "Rendite"


Das Ausbeute Stichwort ist einer von denen Schlüsselwörter in C #, das mich weiter verwirrt, und ich war nie sicher, dass ich es richtig benutze.

Von den folgenden zwei Codeteilen, welches ist das bevorzugte und warum?

Version 1: Ertragsrendite verwenden

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        foreach (Product product in products)
        {
            yield return product;
        }
    }
}

Version 2: Gib die Liste zurück

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        return products.ToList<Product>();
    }
}

792
2018-01-03 22:43


Ursprung


Antworten:


Ich neige dazu, Rendite-Rendite zu verwenden, wenn ich das nächste Element in der Liste (oder sogar die nächste Gruppe von Elementen) berechne.

Mit Ihrer Version 2 müssen Sie die vollständige Liste vor der Rückgabe haben. Bei der Verwendung von Rendite-Rendite müssen Sie wirklich nur den nächsten Artikel haben, bevor Sie zurückkehren.

Dies trägt unter anderem dazu bei, die Rechenkosten komplexer Berechnungen über einen größeren Zeitraum zu verteilen. Wenn die Liste beispielsweise an eine GUI angeschlossen ist und der Benutzer nie zur letzten Seite geht, berechnen Sie nie die endgültigen Elemente in der Liste.

Ein weiterer Fall, in dem Rendite-Rendite vorzuziehen ist, ist, wenn IEnumerable eine unendliche Menge darstellt. Betrachten Sie die Liste der Primzahlen oder eine unendliche Liste von Zufallszahlen. Sie können niemals den vollständigen IEnumerable-Wert auf einmal zurückgeben, daher verwenden Sie yield-return, um die Liste inkrementell zurückzugeben.

In Ihrem speziellen Beispiel haben Sie die vollständige Liste der Produkte, also würde ich Version 2 verwenden.


725
2018-01-03 23:01



Das Füllen einer temporären Liste ist wie das Herunterladen des gesamten Videos, während die Verwendung von yield ist wie das Streaming dieses Videos.


535
2017-07-08 14:14



Als ein konzeptionelles Beispiel für das Verständnis, wann Sie verwenden sollten yieldSagen wir die Methode ConsumeLoop() verarbeitet die zurückgegebenen / zurückgegebenen Artikel ProduceList():

void ConsumeLoop() {
    foreach (Consumable item in ProduceList())        // might have to wait here
        item.Consume();
}

IEnumerable<Consumable> ProduceList() {
    while (KeepProducing())
        yield return ProduceExpensiveConsumable();    // expensive
}

Ohne yieldder Ruf nach ProduceList() könnte lange dauern, weil Sie die Liste vor der Rückkehr ausfüllen müssen:

//pseudo-assembly
Produce consumable[0]                   // expensive operation, e.g. disk I/O
Produce consumable[1]                   // waiting...
Produce consumable[2]                   // waiting...
Produce consumable[3]                   // completed the consumable list
Consume consumable[0]                   // start consuming
Consume consumable[1]
Consume consumable[2]
Consume consumable[3]

Verwenden yield, es wird neu arrangiert, arbeitet irgendwie "parallel":

//pseudo-assembly
Produce consumable[0]
Consume consumable[0]                   // immediately Consume
Produce consumable[1]
Consume consumable[1]                   // consume next
Produce consumable[2]
Consume consumable[2]                   // consume next
Produce consumable[3]
Consume consumable[3]                   // consume next

Und schließlich sollten Sie, wie viele bereits vorgeschlagen haben, die Version 2 verwenden, da Sie die fertige Liste ohnehin schon haben.


59
2017-10-09 21:45



Dies wird wie ein bizarrer Vorschlag erscheinen, aber ich habe gelernt, wie man das benutzt yield Stichwort in C # durch Lesen einer Präsentation über Generatoren in Python: David M. Beazley's http://www.dabeaz.com/generators/Generators.pdf. Sie müssen nicht viel Python wissen, um die Präsentation zu verstehen - ich tat es nicht. Ich fand es sehr hilfreich, nicht nur zu erklären, wie Generatoren funktionieren, sondern auch, warum Sie sich darum kümmern sollten.


26
2018-01-04 21:51



Ich weiß, dass dies eine alte Frage ist, aber ich möchte ein Beispiel dafür nennen, wie das Yield-Keyword kreativ genutzt werden kann. ich habe Ja wirklich profitierte von dieser Technik. Hoffentlich hilft das jedem anderen, der über diese Frage stolpert.

Hinweis: Denken Sie nicht daran, dass das Schlüsselwort yield lediglich eine andere Möglichkeit zum Erstellen einer Sammlung darstellt. Ein großer Teil der Ertragskraft kommt in der Tatsache, dass die Ausführung ist pausiert in deinem Methode oder Eigenschaft, bis der aufrufende Code über den nächsten Wert iteriert. Hier ist mein Beispiel:

Mit dem Yield-Keyword (neben Rob Eisenburgs Caliburn.Micro KoroutinenImplementierung) ermöglicht es mir, einen asynchronen Aufruf an einen Web-Service wie folgt auszudrücken:

public IEnumerable<IResult> HandleButtonClick() {
    yield return Show.Busy();

    var loginCall = new LoginResult(wsClient, Username, Password);
    yield return loginCall;
    this.IsLoggedIn = loginCall.Success;

    yield return Show.NotBusy();
}

Dazu muss mein BusyIndicator aktiviert, die Login-Methode in meinem Webdienst aufgerufen, das Flag IsLoggedIn auf den Rückgabewert gesetzt und der BusyIndicator wieder deaktiviert werden.

So funktioniert das: IResult verfügt über eine Execute-Methode und ein Completed-Ereignis. Caliburn.Micro greift den IEnumerator vom Aufruf von HandleButtonClick () und übergibt ihn an eine Coroutine.BeginExecute-Methode. Die BeginExecute-Methode beginnt mit der Iteration durch die IResults. Wenn das erste IResult zurückgegeben wird, wird die Ausführung in HandleButtonClick () angehalten und BeginExecute () fügt dem Completed-Ereignis einen Ereignishandler hinzu und ruft Execute () auf. IResult.Execute () kann entweder eine synchrone oder eine asynchrone Aufgabe ausführen und feuert das Completed-Ereignis ab, wenn es fertig ist.

LoginResult sieht ungefähr so ​​aus:

public LoginResult : IResult {
    // Constructor to set private members...

    public void Execute(ActionExecutionContext context) {
        wsClient.LoginCompleted += (sender, e) => {
            this.Success = e.Result;
            Completed(this, new ResultCompletionEventArgs());
        };
        wsClient.Login(username, password);
    }

    public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
    public bool Success { get; private set; }
}

Es kann helfen, so etwas einzurichten und durch die Ausführung zu gehen, um zu sehen, was vor sich geht.

Hoffe das hilft jemandem aus! Ich habe es wirklich genossen, die verschiedenen Möglichkeiten zu erforschen, wie Ertrag genutzt werden kann.


24
2018-05-18 04:36



Die zwei Teile des Codes machen wirklich zwei verschiedene Dinge. Die erste Version wird Mitglieder ziehen, wie Sie sie brauchen. Die zweite Version lädt alle Ergebnisse in den Speicher Vor Du fängst an, alles damit zu machen.

Es gibt keine richtige oder falsche Antwort auf diese Frage. Welches ist vorzuziehen, hängt nur von der Situation ab. Zum Beispiel, wenn es ein Zeitlimit gibt, dass Sie Ihre Abfrage vervollständigen müssen und Sie etwas halbkompliziertes mit den Ergebnissen machen müssen, könnte die zweite Version vorzuziehen sein. Aber Vorsicht große Ergebnismengen, vor allem, wenn Sie diesen Code im 32-Bit-Modus ausführen. Ich wurde mehrmals von OutOfMemory-Ausnahmen bei dieser Methode gebissen.

Das Wichtigste dabei ist jedoch: Die Unterschiede liegen in der Effizienz. Daher sollten Sie wahrscheinlich mit demjenigen, der Ihren Code vereinfacht, gehen und ihn erst nach dem Profiling ändern.


12
2018-01-03 23:30



Ertrag hat zwei große Verwendungen

Es hilft, eine benutzerdefinierte Iteration ohne Erstellung von temporären Sammlungen bereitzustellen. (Laden aller Daten und Schleifen)

Es hilft Stateful Iteration zu tun. (Streaming)

Unten ist ein einfaches Video, das ich mit voller Demonstration erstellt habe, um die oben genannten zwei Punkte zu unterstützen

http://www.youtube.com/watch?v=4fju3xcm21M


10
2018-04-05 18:48