Neden <T> Listesini IEnumerable <T> üzerinden kullanmalıyım?


24

ASP.net MVC4 web uygulamamda IEnumerables kullanıyorum, programlamayı mantra izlemeye çalışıyorum, uygulamayı değil.

Return IEnumerable(Of Student)

vs

Return New List(Of Student)

İnsanlar Listeyi IEnumerable değil, kullanmamı söylüyorlar çünkü listeler sorguyu çalıştırılmaya zorlar ve IEumerable kullanmaz.

Bu gerçekten en iyi uygulama mı? Alternatif var mı? Arayüzün kullanılabileceği somut nesneleri kullanarak kendimi garip hissediyorum. Tuhaf hislerim haklı mı?


2
Öncelikle sorguyu yürütmeye zorlamak neden iyi bir şey? İkincisi, bu teknik değerlendirmenin bir yararı olup olmadığını değerlendirmek için veritabanı çağrılarını izlemeniz ve profillemeniz gerekir.
user16764

2
Tüm sorguların yapılması ve modelin görüntüye hazır hale getirilmesi gerektiği söyleniyor. Yani görünüm her şeyi almalı ve veritabanını sorgulamamalıdır.
Rowan Freeman,

3
Bu StackOverflow sorusu oldukça iyi kapsar.
Karl Bielefeldt

Bu iyi bir cevap, ancak bunun MVC ile alaka düzeyini bilmek istiyorum. Neden tüm sorguların tam zamanında çalışabilmesi için görünüme IEnumerables verilemiyor?
Rowan Freeman

2
“Tüm sorguların, modelin görünüm için hazır hale getirilip yüklenebilmesi için yürütülmesi gerektiği söyleniyor. Yani görünüm her şeyi almalı ve veritabanını sorgulamamalı.”. Bu saçma. Bir IEnumerable geçerseniz, görünümünüz veritabanını sorgulayıp sorgulamadığını bilmiyor veya umursamıyor. Ve olması gereken de bu.
user16764

Yanıtlar:


21

ToList()Linq sorguları yaparken , sorgularınızın zamanında ve beklediğiniz sırada yapılmasını sağlamak için önemli olabilecek zamanlar olabilir. Bununla birlikte, bu senaryolar nadirdir ve gerçekte onlara rastlayana kadar hiç kimse endişelenmemelidir.

Uzun lafın kısası, IEnumerablesadece yinelemeye ihtiyaç duyduğunuzda kullanın IList, doğrudan indekslemeniz gerektiğinde kullanın ve dinamik olarak boyutlandırılmış bir diziye ihtiyacınız varsa kullanın (sabit boyutlu bir dizide dizine ihtiyacınız varsa, sonra standart bir diziyi kullanın).

Yürütme zamanı şey gelince, her zaman bir şekilde bir listeyi kullanabilirsiniz IEnumerableböylece dönmek çekinmeyin, değişken IEnumerablebir yaparak .ToList();bir gibi bir parametrede veya pas IEnumerableyürüterek .ToList()üzerine IEnumerableorada sağa sonra kuvvete yürütme ve. Sadece, yürütmeyi ne zaman zorladığınıza, .ToList()bunu yaptığınız IEnumerabledeğişkeni asmayacağınıza ve tekrar çalıştıracağınıza dikkat edin, aksi takdirde LINQ sorgunuzdaki yinelemeleri gereksiz yere iki katına çıkarırsınız.

MVC ile ilgili olarak, burada dikkat edilmesi gereken özel bir şey yoktur. .NET'in geri kalanıyla aynı yürütme zamanı kurallarına uyacak, sanırım geçmişte gecikmiş yürütme anlambiliminin neden olduğu karışıklıktan dolayı biraz karıştığınız ve bunu bir şekilde ilgili olduğunu söyleyen MVC'den suçluyor olabilirsiniz. değil. Gecikmeli yürütme semantiği ilk başta herkesi şaşırtıyor (ve hatta bir süre sonra bile; onlar zor bir dokunuş olabilir). Yine de, bir LINQ sorgusunun iki kez yürütülmemesini veya başka bir koda göre belirli bir sırada çalıştırılmasını zorunlu kılana kadar gerçekten endişelenmeyin, bu noktada değişkeninizi kendinize atayın. ToList () yürütmeyi zorlamak ve iyi olacaksın.


IEnumerables görünümü vermek kötü mü? Sorguları, görünüm onları geldiğinde yürütülmüş olacak şekilde Listeler vermeli mi?
Rowan Freeman,

@RowanFreeman Buna cevap vermek için bir düzenleme ekledim. Tamamen anlamadıkları bir şeye rastlayan birini (onları suçlayamaz, geciktirilmiş infaz ciddi şekilde karmaşık ve kafa karıştırıcıdır) düşünüyorum ve gecikmiş infazın tam davranışını anlamaya çalışmak yerine kötü joojoo'ya tebeşirle yazdı semantik.
Jimmy Hoffa

Güzel cevap O zaman gerçekten kullanmam gerekecek mi .ToList ()? Şimdiye kadar benim uygulama sadece IEnumerables kullanarak ve onları modelden görünüme geçirerek iyi çalışıyor. Liste Yok veya .ToList (). Sorum işlevsellikten değil - uygulamamın çalıştığını biliyorum. Benim sorum en iyi uygulamalardan biri.
Rowan Freeman

4
@RowanFreeman'ın en iyi uygulaması, hala gereksinimlerinizi karşılayan minimal arayüzü kullanmaktır. IEnumerable bunu sizin için şimdi yapıyor, bu yüzden onu değiştirmek için endişelenmeyin. Bununla birlikte, 3 veya 10 kez yürütülen bir sorgunuz olduğunda ve nedenini anlamadığınızda veya bir sorgunun yalnızca daha sonra çalıştığını bulmak için bir eklemeden önce yürütülmesini bekleyeceğiniz bir gün gelecek. Bunlar, tanımanız gereken zamanlardır. () istediğiniz zaman yürütmeyi zorlayacak ve bir LINQ sorgusundan bir IEnumerable değerini birden çok kez tekrarlamak tüm sorguyu birden çok kez yürütecektir; Bu olaylar gerçekleştiğinde infazınızı düzeltin
Jimmy Hoffa

1
Kullanmamalısınız - Listatlamak List, listenin içeriğinin değiştirileceği anlamına gelir. Bir koleksiyona dönmek istiyorsanız, kullanın IReadOnlyCollection. ListMetotlar içinde kullanım ve listeyi değiştiren metotlar arasındaki değişim içindir. Bu kadar!
ErikE

7

İki sorun var.

IENumerable<Data> query = MyQuery();

//Later
foreach (Data item in query) {
  //Process data
}

"İşlem Verileri" döngüsüne ulaşıldığında, sorgu artık geçerli olmayabilir. Örneğin, sorgu zaten Atılmış bir DataContext'te çalışıyorsa, kodunuz bir istisna atar. Bu tür bir şey, bir sorguyu yarattığınız yerden farklı bir bağlamda işlerken kafa karıştırıcı hale gelir.

İkincil bir sorun, "İşlem Verileri" döngüsü tamamlanıncaya kadar bağlantınızın serbest bırakılmamasıdır. Bu, yalnızca "İşlem Verileri" karmaşıksa bir sorundur. Bu, http://msdn.microsoft.com/en-us/library/bb386929.aspx adresinde belirtilmiştir :

S. Veritabanı bağlantım ne kadar süre açık kalacak?

A., sorgu sonuçlarını tüketene kadar bir bağlantı genellikle açık kalır. Tüm sonuçları işlemek için zaman ayırmayı planlıyorsanız ve sonuçları önbelleğe almak istemiyorsanız, sorguyu ToList'e uygulayın. Her nesnenin yalnızca bir kez işlendiği genel senaryolarda, akış modeli, DataReader ve LINQ to SQL'de üstündür.

Bu nedenle, bu sorunlar, sorgunun gerçekten yürütülmesini sağlamak için teşvik edilmenizin nedenidir, örneğin arayarak ToList(). Ancak, Jimmy Suggest'in dediği gibi, Listenizi bir IEnumerable olarak geri döndürmekten alıkoyacak bir şey yok.

Genel bir kural olarak, bir IEnumerable üzerinde birden fazla kez yinelemekten kaçınılmasını öneririm. Kodunuzun tüketicilerinin bu kurala uyduğunu varsayarsak, sorguyu iki kez uygulayarak birisinin veritabanına iki kez vurabileceği endişesini düşünmüyorum.


1

IEnumerableErken numaralandırmanın bir başka yararı da istisnaların uygun yere atılmasıdır. Bu hata ayıklamaya yardımcı olur.

Örneğin, Razor görünümlerinizden birinin içinde bir kilitlenme istisnası varsa, veri erişim yöntemlerinden birinde sırasında istisna olmuş gibi net olamaz.


IEnumerableBunu atabilecek herhangi bir yöntem , muhtemelen hata yapıyordur. Ertelenen IEnumerableyöntemler ikiye bölünmelidir: ertelenmiş olmayan yöntem parametreleri kontrol eder ve gerekliyse fırlatıp ayarlar (boş bir argüman nedeniyle). Sonra özel uygulamaya bir çağrı döndürür edilir ertelenmiş. Ben açıklamalarım Cevabınız taban tabana zıt olduğunu sanmıyorum, ama senin cevap önemli bir yönü, dışarı bıraktım olduğunu düşünüyorum kullanmanın semantik anlam IEnumerablevs bir List(mutasyon) vs IReadOnlyCollection(hiç bir yarar erteleme) .
ErikE
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.