Hallo Leute
Kann mir bitte jemand sagen was man verwenden sollte und vorallem wieso :
1. Yield return
public IEnumerable<Product> GetAllProducts()
{
using (myEntities db = new myEntities ())
{
var products = from product in db.Product
select product;
foreach (Product product in products)
{
yield return product;
}
}
}
2. Return List<T>
public IEnumerable<Product> GetAllProducts()
{
using (myEntities db = new myEntities())
{
var products = from product in db.Product
select product;
return products.ToList<Product>();
}
}
Stimmt folgendes :
--> Yield gibt das resultat "nacheinander zurück" somit vorteilhaft (schneller) wenn das Resultat per Binding an das UI gebunden wird ?
(Yield macht nur Sinn wenn die Klasse INotifyPropertyChange implementiert ?!)
Danke für Eure Antworten um Licht in die Dunkelheit zu bringen 😃
Beste Grüsse
Diräkt
Der unterschied zwichen den beiden Varianten ist, dass der ohne yield alle Ergebnisse beim ersten durchlaufen an der Stelle
return products.ToList<Product>();
gesammelt werden. Wenn man die Methode mit yield so verwendet:
var e = GetAllProducts();
foreach(var product in e){
...
wird in der Zeile GetAllProducts() die Methode bis zum ersten yield ausgeführt. Dann geht es weiter zum foreach. Dort wird das erste Ergebnis ausgelesen und die Methode läuft weiter bis zum nächsten usw..
Ich denke einen Performancevorteil bringt es nicht wirklich, bis vllt auf einen Speichergewinn bei einem großen Ergebnis bei dem man viele Ergebnisse aus der Datenbank lädt und dann verarbeitet (wenn man sie in kleinen stücken rauslädt. So bleibt nur ein kleiner Teil im Speicher, und es wird nicht sofort alles geladen.
Bei linq ist es ähnlich.
var products = from product in db.Product
select product;
baut im Grunde erst das Statement zusammen. Erst wenn man da durch itteriert werden die Ergebnisse geladen.
Yield gibt das resultat "nacheinander zurück" somit vorteilhaft (schneller) wenn das Resultat per Binding an das UI gebunden wird ?
Japp, yield baut eine state maschine. Z.B. in Yield, and the C# state machine hat jemand das mal genauer angeschaut.
In manchen Situationen sicherlich schneller, aber im Speziellem Falle muss das nicht unbedingt so sein.
Die Länge ist bei yield return nicht bekant, bevor der gesamte Enumerator durchlaufen wurde. Deshalb muss eventuell sowieso ne Liste erstellt werden oder der Enumerator wird mehrfach durchlaufen. Außerdem handelst du dir mit yield leichter Threading-Probleme ein.
Hi Diräkt,
in deinem konkreten Fall sind aber deine beiden Varianten ungünstig.
Nimm einfach
public IEnumerable<Product> GetAllProducts()
{
using (myEntities db = new myEntities ())
{
var products = from product in db.Product
select product;
return products;
}
}
Der Linq-Ausdruck liefert ja ein IQueryable<Product> zurück, und da IQueryable<T> von IEnumerable<T> abgeleitet ist, kannst du diesen Ausdruck "diräkt" 😁 so zurückgeben.
Hallo Cat,
deine Variante ist problematisch, da Du den ObjectContext disposed und bei einer späteren Evaluierung (z.b. mit ToList) der Zugriff fehlschlägt (da db
dann bereits disposed ist).
Siehe auch: ObjectContext instance has been disposed problem while binding
Ups, daran habe ich gar nicht gedacht (ich habe nur das "using" so übernommen...)
Ok, aber normalerweise sollte dann die Entity-Instanz besser eine Membervariable der Klasse sein, also:
private myEntities db = new myEntities();
public IEnumerable<Product> GetAllProducts()
{
var products = from product in db.Product
select product;
return products;
}
Besten Dank für Eure Antworten.
@Cat
Ok, aber normalerweise sollte dann die Entity-Instanz besser eine Membervariable der Klasse sein, also:
Dies wäre bei einem WebApp Projekt wohl nicht sehr sinvoll ?!
Beste Grüsse
Diräkt
Hallo zusammen,
generell würde ich ein "LINQ-ToDB Ausdruck" aus den gegebenen Gründen nie direkt zurückgeben.
Auch, weil man nie genau wissen kann, ob mehrfaches Iterieren nicht am Ende mehrfach die DB abfrägt (wäre performancetechnisch fatal!).
Zur Variante mit dem yield return
: Das ist vollkommen unsinnig und löst auch das Problem nicht.
yield return
ist vor allem da sinnvoll, wo man selbst ein Enumerator bauen möchte z.B. (nehmen wir an, man hätte kein Enumerable.Range 😉 ):
public IEnumerable<int> GetNumbers(int upper)
{
for (int i = 0; i < upper; i++)
yield return i;
}
Statt ToList würde ich jedoch ToArray verwenden, wenn der Rückgabewert sowieso ein IEnumerable<T> ist - schreibend kann man ja sowieso nicht mehr darauf zugreifen; also:
public IEnumerable<Product> GetAllProducts()
{
using (myEntities db = new myEntities())
return db.Product.ToArray();
}