LINQ'nun en zor ya da yanlış anlaşılan yönü nedir? [kapalı]


282

Arka plan: Önümüzdeki ay boyunca, hakkında en azından hakkında LINQbağlamda üç görüşme yapacağım C#. İnsanların neyi anlamakta zorlandıklarına veya neyin yanlış bir izlenime sahip olabileceğine bağlı olarak hangi konuların adil bir şekilde dikkat edilmeye değer olduğunu bilmek istiyorum. Özellikle söz edilmeyecektir LINQiçin SQLhariç sorguları uzaktan (genellikle ve ifade ağaçları kullanarak çalıştırılabilir nasıl örnek olarak veya Varlık Framework IQueryable).

Peki, ne hakkında zor buldun LINQ? Yanlış anlamalar konusunda ne gördünüz? Örnekler aşağıdakilerden herhangi biri olabilir, ancak lütfen kendinizi sınırlamayın!

  • C#Derleyici sorgu ifadelerini nasıl ele alır?
  • Lambda ifadeleri
  • İfade ağaçları
  • Genişletme yöntemleri
  • Anonim türler
  • IQueryable
  • Ertelenmiş ve derhal icra
  • Akışa karşı arabelleğe alınmış yürütme (ör. OrderBy ertelendi, ancak arabelleğe alındı)
  • Örtük olarak yazılan yerel değişkenler
  • Karmaşık genel imzaları okuma (örneğin Enumerable.Join )

3
Bu görüşmeleri ne zaman yapacağınızı bilmek isterim ve bunları çevrimiçi görüntülemenin herhangi bir yolu varsa
Mark Heath

2
İlk konuşma: Kopenhag, 30 Ekim. Umarım bu bantlanacaktır. (Bütün gün!) İkinci konuşma: Londra, 19 Kasım akşamı Londra .NET Kullanıcıları Grubu, muhtemelen Push LINQ'da. Üçüncü konuşma: Okuma, 22 Kasım, Geliştirici Geliştirici Günü, 60 dakika içinde Nesnelere LINQ uygulanması.
Jon Skeet

1
Downvoters: Lütfen açıklayıcı bir yorum ekleyin.
Jon Skeet

2
@Jon, Üzgünüm, ama bunu kapatmam gerekiyor.
Tim Post

3
@Tim: Yeterince adil - daha fazla yanıt almıyordu. Şahsen ben düşünüyorum did yapıcı olmak sonuna seçebilirdi - Kesinlikle insanların zor bulmak ne olduğunu görmek için yararlı buldum. Muhtemelen şimdi sormazdım ...
Jon Skeet

Yanıtlar:


271

Gecikmeli yürütme


12
Righto - bu açıkça bu soru için en önemli şey olan okuyucular arasında favori. Karışıma "arabelleğe alma ve aktarım" ı da ekleyeceğim, çünkü bu yakından ilişkili - ve genellikle kitaplarda görmek istediğim kadar ayrıntılı olarak tartışılmıyor.
Jon Skeet

10
Gerçekten mi? Linq öğrenirken tembel yüklü bir doğa bana defalarca işaret etmişti, bu benim için asla bir sorun değildi.
Adam Lassek

26
ALassek ile aynı fikirde. MSDN belgeleri LINQ'nun tembel değerlendirme niteliğini açıkça belirtmektedir. Belki asıl sorun, geliştiricilerin tembel programlama doğasıdır ... =)
Seiti

4
... özellikle de LINQ 2 SQL için değil, nesneler için LINQ için de geçerli olduğunu fark ettiğinizde - aynı öğe listesi üzerinden numaralandırdığınızda öğelerin bir listesini almak için 10 web yöntemi çağrısı gördüğünüzde ve liste zaten değerlendirildi
Simon_Weaver

5
Getiri ifadesinin ne olduğunu ve nasıl çalıştığını bilmek, IMHO'nun LINQ hakkında kapsamlı bir anlayış için kritik öneme sahiptir.
09:00

125

Ertelenmiş yürütme kavramının şimdiye kadar bana yenilmesi gerektiğini biliyorum, ancak bu örnek gerçekten pratik bir kavrayış elde etmeme yardımcı oldu:

static void Linq_Deferred_Execution_Demo()
{
    List<String> items = new List<string> { "Bob", "Alice", "Trent" };

    var results = from s in items select s;

    Console.WriteLine("Before add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }

    items.Add("Mallory");

    //
    //  Enumerating the results again will return the new item, even
    //  though we did not re-assign the Linq expression to it!
    //

    Console.WriteLine("\nAfter add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}

Yukarıdaki kod aşağıdakileri döndürür:

Before add:
Bob
Alice
Trent

After add:
Bob
Alice
Trent
Mallory

2
blogs.msdn.com/b/charlie/archive/2007/12/09/… <- Bence bu açıklamak için en iyi blog. (2007'den bu yana, zaten bu kadar uzun süredir olduğuna inanamıyorum)
Phill

104

Orada sadece daha fazla olduğunu LINQiçin SQLve özellikler daha adil bir daha vardır SQLdilde gömülü ayrıştırıcı.


6
Ben bence herkes bu hasta: /
TraumaPony

40
Herkes değil! Hala SQL LINQ nedir bilmiyorum ve lanet zaman LINQ kullanın.
Robert Rossney

2
Ben LINQ kullanarak bir şey denemek ve açıklamak çok rahatsız olur ve diğer kişi sadece bana bakar ve "ohhh Ben böyle bir şey için LINQ kullanmıyorum, sadece SQL" diyor :(
Nathan W

13
Anlaşılan, birçok insan LINQ'nun genel amaçlı bir araç olduğunu anlamıyor gibi görünüyor.
Matthew Olenik

86

Büyük O gösterimi . LINQ, ne yaptığınızı bilmiyorsanız, O (n ^ 4) algoritmalarını fark etmeden yazmayı inanılmaz derecede kolaylaştırır.


16
Bir örnek ne dersiniz?
hughdbrown

4
Örnek olarak, belki de bir Select yan tümcesinin, her birinin kayıt kümesinin tamamında başka bir geçişe neden olan birçok Sum () operatörü içermesinin çok kolay olduğu anlamına gelir.
Rob Packwood

1
Aslında, büyük O gösteriminin ne olduğunu ve neden önemli olduğunu ve verimsiz sonuç sorgularının bazı örneklerini incelemeye değer olabilir. Orijinal posterin önerdiğini düşünüyorum, ama yine de bahsettiğimi düşündüm. - EDIT: sadece bu yazı 1.5 yaşında olduğunu fark :-)
zcrar70

7
Bu O (n ^ x), O (xn), sadece O (n) olurdu.
Malfist

3
Birleştirme işleci olmadan birleştirme yapmaya çalışmak O (n ^ x) ile sonuçlanır: i1'deki aralık1'deki i2'den aralık2'deki i3'ten aralık3'teki i4'ten i4 == i2 && i3 == i4 yeni {i1, i2, i3, i4}. Ve bunu daha önce yazılmış olduğunu gördüm. Çalışıyor, ama çok yavaş.
MarkPflug

55

Bir Lambdaifadenin hem bir ifade ağacına hem de anonim bir temsilciye çözümlenebileceğini düşünüyorum , böylece aynı bildirim lambdaifadesini hem IEnumerable<T>uzantı yöntemlerine hem de uzantı yöntemlerine iletebilirsiniz IQueryable<T>.


2
Kabul. Ben bir emektarım ve ben kendi QueryProvider
TheSoftwareJedi

53

Götürdü yolu gibi birçok LINQ uzantısı yöntemleri olduğunu fark için çok uzun Single(), SingleOrDefault()vb lambdas almak aşırı yüklenmeleri var.

Yapabilirsin :

Single(x => x.id == id)

ve bunu söylemeye gerek yok - bazı kötü eğiticiler beni alışkanlık haline getirdi

Where(x => x.id == id).Single()

+1, çok güzel. Bunu aklımda tutacağım.
Pretzel

4
Bunu da unutmaya devam ediyorum. Count()Diğerleri arasında da geçerlidir . Kod okunabilirliğinin belirgin bonusuna ek olarak herhangi bir performans farkı olup olmadığını biliyor musunuz?
Justin Morgan

1
Üniversitede, hocam bu aşırı yükleri kullanmak için puan almak istedi !! Yanlış olduğunu kanıtladım!
TDaver

12
Garip gelebilir ama ikinci sözdizimini tercih ederim. Daha okunabilir buluyorum.
Konamiman

40

LINQ to SQL'de sürekli olarak insanların DataContext'i, nasıl kullanılabileceğini ve nasıl kullanılması gerektiğini anlamadığını görüyorum. Çok fazla kişi, ne olduğuna dair DataContext'i (kalıcı bir nesne değil, bir İş Birimi nesnesi) görmüyor.

Ben insanların her işlem için yeni bir zaman yapmak yerine bir DataContext / session it / etc singleton çalışıyoruz kez gördüm.

Ve sonra IQueryable değerlendirilmeden önce DataContext atılır, ancak bu, IQueryable'ı anlamayan insanlarla DataContext'ten daha çok bir propata sahiptir.

Çok fazla karışıklık gördüğüm diğer kavram ise Query Syntax ve Expression Syntax. Bu noktada en kolay olanı kullanacağım, genellikle İfade Sözdizimi'ne bağlı kalacağım. Birçok insan sonunda aynı şeyi üreteceklerini hala anlamıyorlar, Sorgu her şeyden önce İfadeye derlendi.


2
Uyarı: Çalışma birimi, veri bağlamını tek bir seçenek olarak içeren küçük bir program olabilir.
graffic

15
DataContext'i tek birtonda kullanmamalısınız, iş parçacığı için güvenli değildir.
Aaron Powell

3
@Slace, tüm programlar çok yönlü değildir, bu nedenle bir çok "masaüstü" yazılımında DataContext'i bir singleton olarak kullanmak sorun değildir
Ian Ringrose 16

2
İlk LINQ to SQL projesini yaptığımda (DataContext'i bir singleton kullanarak) bu tarafından ısırıldı. Belgelerin ve kitapların bunu yeterince açıkladığını sanmıyorum. Aslında, ismin geliştirilebileceğini düşünüyorum, ama nasıl yapılacağından emin değilim.
Roger Lipscombe

1
Bunu kafamda dövmek için ScottGu'nun Linq'deki artivlesini defalarca okumak gerekiyordu.
Evan Plaice

34

Bence LINQ yanlış anlaşılmış kısmı bir olmasıdır dil uzatma değil, bir veritabanı uzantısı veya yapı.

LINQçok daha fazla LINQ to SQL.

Artık çoğumuz LINQkoleksiyonlarda kullandığımıza , ASLA geri dönmeyeceğiz!

LINQ 2.0'da Generics ve 3.0'da Anonim Türlerden bu yana .NET'in en önemli tek özelliğidir.

Ve şimdi Lambda'ya sahibiz, paralel programlama için sabırsızlanıyorum!


Anonim türlerden daha önemli ve hatta jeneriklerden bile daha önemli diyebilirim.
Justin Morgan

26

Birisi için, ifade ağaçlarının ne olduğunu ve nedenini bilmem gerekip gerekmediğini bilmek istiyorum.


6
Sanırım ifade ağaçlarının ne olduğunu ve neden var olduklarını bilmeye değer, ama onları nasıl inşa edeceğinizin ayrıntıları değil. (Elle inşa etmek bir acıdır, ancak derleyici bir lambda ifadesini dönüştürürken harika bir iş çıkarır.)
Jon Skeet

3
Aslında, ifade ağaçlarında birkaç blog girişi yapmayı düşünüyordum (çünkü onları "aldım"). Ifade ağaçları manipüle çok yararlı buluyorum ...
Marc Gravell

Ancak, Jon'un konuşmaları için yararlı olduklarını sanmıyorum ;-p
Marc Gravell

3
Sadece ifade ağaçlarının verim ifadesi gibi olacağından endişe ediyorum: ilk başta ne olduğunu anlamadığım halde inanılmaz derecede değerli olan bir şey.
Robert Rossney

1
Marc Gravell Konuyla ilgili blog girişlerinizi okumak isterim. Dört gözle bekliyorum
Alexandre Brisebois

20

LINQ için oldukça yeniyim. İşte ilk denememde tökezlediğim şeyler

  • Birden fazla sorguyu bir araya getirme
  • Visual Studio'da LINQ sorgularında etkin hata ayıklama.

21
LINQ hata ayıklama tek başına ve önemli bir konudur. LINQ'nun en büyük zayıflığı, adım adım ilerleyemeyeceğiniz keyfi olarak karmaşık mantık blokları yazmanıza izin vermesidir.
Robert Rossney

3
bunlar LINQ pedini kullanmak için iyi bir yer olabilir
Maslow

2
Yürekten katılıyorum; bu yüzden LINQ Sırları Açığa Çıktı: Zincirleme ve Hata Ayıklama'yı yeni Simple-Talk.com'da yayınladım, yardım bulabileceğinizi yazdım.
Michael Sorens

Evet, LinqPad, LINQ sorgularınızı geliştirmek için harika bir ikincil araçtır. Özellikle başlangıçta ve sözleşmelerde / kalıplarda yenisiniz.
Buffalo

20

Farkındayım aslen olmadıkları şey LINQ sözdizimi olmasıydı gelmez gerektiren IEnumerable<T>veya IQueryable<T>işe, LINQ sadece desen eşleştirme ile ilgili.

alt metin http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

İşte cevabı (hayır, değil mi o blog yazma Bart De Smet yaptı ve LINQ I ettik Found iyi blogcular biri).


1
Bu blog gönderisini de ilginç bulabilirsiniz: msmvps.com/blogs/jon_skeet/archive/2008/02/29/…
Jon Skeet

Güzel yazı Jon (Blogunuza abone oldum, ancak son zamanlarda olsa da).
Aaron Powell

19

Hala "let" komutuyla (ki bunun için bir kullanım bulamadım) ve SelectMany (ki kullandım, ama doğru yaptığımdan emin değilim) ile sorun yaşıyorum


2
Bir değişkeni tanıtmak istediğinizde let ifadesini kullanabilirsiniz. İçine değişkenler eklediğiniz ve her değişkene kodun okunabilirliğine yardımcı olacak bir ad verdiğiniz geleneksel bir döngü düşünün. Bazen, bir işlev sonucunu değerlendiren bir let deyimine sahip olmanız da hoş olur; bu, sonucu iki kez değerlendirmek zorunda kalmadan seçip sipariş verebilirsiniz.
Rob Packwood

'let' kompozit tipler yapmanıza izin verir. Kullanışlı şeyler.
Phill

19

Linq sağlayıcıları arasındaki soyutlamanın ne zaman sızdığını anlamak. Bazı şeyler nesneler üzerinde çalışır ancak SQL üzerinde çalışmaz (örneğin, .TakeWhile). Bazı yöntemler SQL'ye (ToUpper) çevrilebilirken, diğerleri kullanılamaz. Bazı teknikler, diğerlerinin SQL'de daha etkili olduğu nesnelerde daha etkilidir (farklı birleştirme yöntemleri).


1
Bu çok iyi bir nokta. Intellisense'in TÜMÜNÜ size göstermesine yardımcı olmaz ve genellikle derlenir. Sonra çalışma zamanında patlarsınız. Umarım VS 2010, ilgili uzantı yöntemlerini göstermede daha iyi bir iş çıkarır.
Jason Short

12

Birkaç şey.

  1. İnsanlar Linq SQL Linq olarak düşünüyor.
  2. Bazı insanlar, bu performans sonuçlarını dikkate almadan tüm foreach / mantığı Linq sorgularıyla değiştirmeye başlayabileceklerini düşünüyor.

11

Tamam, talep nedeniyle, bazı İfade şeyler yazdım. Blogger ve LiveWriter'ın bunu biçimlendirmek için nasıl komplo kurduklarından% 100 memnun değilim, ama şimdilik yapacak ...

Her neyse, işte gidiyor ... Özellikle insanların daha fazla bilgi istediği alanlar varsa, herhangi bir geri bildirim almak isterim.

İşte , öyle ya da nefret ediyorum ...


10

Bazı hata mesajları, özellikle LINQ SQL için oldukça kafa karıştırıcı olabilir. sırıtış

Herkes gibi birkaç kez ertelenmiş infaz tarafından ısırıldım. Benim için en kafa karıştırıcı şey SQL Server Sorgu Sağlayıcısı ve ne yapabilirsiniz ve onunla yapamam olduğunu düşünüyorum.

Hala bazen boş olan bir ondalık / para sütununda bir Sum () yapamaman beni şaşırtıyor. DefaultIfEmpty () kullanmak işe yaramaz. :(


1
Bir tokat tokatlamak gibi davranmak bir toplam çalışmak için bu sorguda Nerede
Esben Skov Pedersen

9

LINQ'da ele alınması gereken harika bir şey, performans açısından kendinizi nasıl başaracağınızdır. Örneğin, bir döngü koşulu olarak LINQ sayısını kullanmak gerçekten akıllı değildir.


7

IQueryable, her ikisini de kabul eder Expression<Func<T1, T2, T3, ...>>ve Func<T1, T2, T3, ...>2. durumda performans düşüşü hakkında bir ipucu vermeden.

İşte ne demek istediğimi gösteren kod örneği:

[TestMethod]
public void QueryComplexityTest()
{
    var users = _dataContext.Users;

    Func<User, bool>                funcSelector =       q => q.UserName.StartsWith("Test");
    Expression<Func<User, bool>>    expressionSelector = q => q.UserName.StartsWith("Test");

    // Returns IEnumerable, and do filtering of data on client-side
    IQueryable<User> func = users.Where(funcSelector).AsQueryable();
    // Returns IQuerible and do filtering of data on server side
    // SELECT ... FROM [dbo].[User] AS [t0] WHERE [t0].[user_name] LIKE @p0
    IQueryable<User> exp = users.Where(expressionSelector);
}

Açıklayabilir misin? Takip etmiyorum ...
Pretzel

@Pretzel Sorunumu gösteren kod örneği ekledim.
Valera Kolupaev

Kod örneği için teşekkürler! Çok yararlı.
Buffalo

6

Yanlış anlaşılmış olarak nitelendirilip nitelenmediğini bilmiyorum - ama benim için sadece bilinmiyor.

DataLoadOptions ve belirli bir sorgu yaptığımda hangi tabloların birleştirildiğini nasıl kontrol edebildiğimi öğrenmek beni memnun etti.

Daha fazla bilgi için buraya bakın: MSDN: DataLoadOptions


6

LINQ en yanlış anlaşılmış (ya da anlaşılmaması gerekir?) Yönü IQueryable ve özel LINQ sağlayıcıları olduğunu söyleyebilirim .

Bir süredir LINQ kullanıyorum ve IEnumerable dünyasında tamamen rahatım ve LINQ ile ilgili çoğu sorunu çözebilirim.

Ama IQueryable, İfadeler ve özel linq sağlayıcıları hakkında incelemeye ve okumaya başladığımda başımı döndürdü. Oldukça karmaşık bir mantık görmek istiyorsanız, LINQ to SQL'in nasıl çalıştığına bakın.

Ben LINQ bu yönünü anlamak için sabırsızlanıyoruz ...


6

Çoğu insanın söylediği gibi, en yanlış anlaşılan kısmın LINQ'nun T-SQL için sadece bir yedek olduğunu varsaydığını düşünüyorum. Menajerim gördüğü TSQL gurusu olarak kendini bize projede LINQ kullanmak ve hatta böyle bir şeyi serbest bırakılması için MS nefret izin vermedi !!!


Çok fazla insan TSQL'in yerine kullanıyor. Birçoğu bir infaz planını hiç duymamıştı.
erikkallen

+1 çünkü yöneticinize katılıyorum, en azından herhangi bir projede LINQ'nun SQL'e izin vermesi kadar. LINQ to Objects tamamen başka bir konudur.
NotMe

5

Bir sorgu yürütüldüğünde var neyi temsil eder?

O mi iQueryable, iSingleResult, iMultipleResultveya does it uygulanmasına göre değişir. Dinamik yazarak (C #) standart statik yazmaya karşı (olduğu gibi) bazı spekülasyonlar var.


AFAIK var her zaman söz konusu somut sınıftır (anonim bir tür olsa bile), bu yüzden asla IQueryable, ISingleResult veya 'I' ile başlayan herhangi bir şey ('I' ile başlayan somut sınıflar uygulanmayacaktır).
Motti

5

Bir döngüyü iç içe yerleştirmenin ne kadar kolay olduğunu herkesin anladığını sanmıyorum.

Örneğin:

from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem

+1, whoa. bu oldukça güçlü.
Pretzel

4

group by hala başımı döndürüyor.

Ertelenmiş yürütme ile ilgili herhangi bir karışıklık, basit bir LINQ tabanlı koddan geçerek ve izleme penceresinde oynayarak çözülebilir olmalıdır.


1
Ben eğlence için Nesneler için biraz LINQ uygulamak gerçekten yardımcı olduğunu buldum :) Ama evet, biraz kafa karıştırıcı - kesinlikle bir süredir herhangi bir LINQ yapmadıysanız imzalara geri dönmek zorunda. Aynı şekilde "katılmak" vs "katılmak" sık sık beni alır ...
Jon Skeet

4

Derlenmiş Sorgular

Eğer edemez zincir aslında IQueryableonlar yöntem çağrıları, çünkü (iken hala ve başka bir şey ama SQL çevirilebilir!) O mindboggling ve DRY büyük bir ihlalini oluşturur edilir etrafında o işin neredeyse imkansız olduğunu söyledi. Benim IQueryablederlenmiş sorguları (sadece ağır senaryolar için derlenmiş sorgu var) yok, ama derlenmiş sorgularda onları kullanamazsınız ve bunun yerine tekrar düzenli sorgu sözdizimi yazmanız gerekir. Şimdi 2 yerde aynı alt sorguları yapıyorum, bir şey değiştiğinde her ikisini de güncellemeyi hatırlamalıyım vb. Bir kabus.


4

LINQ to SQL ile ilgili # 1 yanılgısı, etkili bir şekilde kullanabilmek için STILL SQL bilmek zorunda olduğunu düşünüyorum.

Linq to Sql ile ilgili bir başka yanlış anlaşılmış şey, hala çalışması için veritabanı güvenliğinizi saçma noktasına düşürmeniz gerektiğidir.

Üçüncü nokta, Linq to Sql'nin Dynamic sınıflarıyla birlikte kullanılması (yani, sınıf tanımının çalışma zamanında oluşturulduğu anlamına gelir) muazzam miktarda tam zamanında derlemeye neden olur. Bu kesinlikle performansı öldürebilir.


4
Bununla birlikte, SQL'i zaten bilmek çok faydalıdır. Linq to SQL (ve diğer ORM'ler) tarafından yayılan bazı SQL düpedüz şüpheli olabilir ve SQL bilmek bu tür sorunları teşhis etmeye yardımcı olur. Ayrıca, Linq to SQL saklı yordamlar kullanabilirsiniz.
Robert Harvey


2

Belirtildiği gibi, tembel yükleme ve ertelenmiş yürütme

LINQ to Objects ve LINQ to XML (IEnumerable), LINQ'dan SQL'e nasıl farklıdır (IQueryable)

NASIL tüm katmanlarda LINQ ile veri erişim katmanı, İş Katmanı ve Sunum Katmanı inşa .... ve iyi bir örnektir için.


Yapabileceğim ilk ikisi. Üçüncüsünü "bunu yapmak için doğru yol bu" anlamda yapmaya çalışmak istemiyorum ...
Jon Skeet

+1, siz bunu işaret edene kadar, LINQ-to-Objects ve LINQ-to-XML'in IQueryable olarak LINQ-to-SQL yerine IEnumerable olduğunu fark etmemiştim, ama mantıklı. Teşekkürler!
Pretzel

2

Çoğu insanın söylediği gibi, en yanlış anlaşılan kısmın LINQ'nun T-SQL için sadece bir yedek olduğunu varsaydığını düşünüyorum. Kendini bir TSQL gurusu olarak gören yöneticim, projemizde LINQ kullanmamıza izin vermeyecek ve hatta böyle bir şeyi serbest bırakmak için MS'den nefret edecek!


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.