LINQ (Language Integrated Query), dizileri filtrelemek, dönüştürmek, sıralamak, gruplamak ve özetlemek için bir metot kütüphanesidir. using System.Linq; ekleyin; her dizi, List<T>, Dictionary ve diğer IEnumerable<T>, her biri tek bir elemanla ne yapılacağını söyleyen bir lambda alan Where, Select ve OrderBy gibi metotlar kazanır.
İlk sorgu: metot sözdizimi ve sorgu sözdizimi
LINQ'in iki gösterimi vardır. Metot sözdizimi çağrıları zincirler; sorgu sözdizimi SQL gibi okunur. Derleyici sorgu sözdizimini aynı metot çağrılarına çevirir, bu yüzden aynı sonuçları üretirler.
Çıktı:
95, 91, 88
95, 91, 88
Modern kodda metot sözdizimi daha yaygındır ve bazı operatörler (Take, Distinct, Count, First, ToList) yalnızca metot olarak vardır. Sorgu sözdizimi join'lerde ve let ile ara değişkenler tanıtan sorgularda parlar. Bu sayfanın geri kalanı metot sözdizimini kullanır ve bir şey kattığı yerde sorgu sözdizimini gösterir.
Where ve Select: filtrelemek ve projeksiyon
Where bir koşulu karşılayan elemanları tutar. Select her elemanı başka bir şeye dönüştürür. Birlikte günlük sorguların çoğunu karşılarlar.
Çıktı:
Mug, Kettle
MUG $8.50 | LAMP $32.00 | KETTLE $27.00 | RUG $120.00
Lamp: 38.40
Rug: 144.00
1. Mug 2. Lamp 3. Kettle 4. Rug
Where elemanları asla değiştirmez, Select de kaç tane olduklarını asla değiştirmez. new { p.Name, WithTax = ... } anonim bir tip oluşturur: derleyicinin sizin için yazdığı, property'lerini normal nokta sözdizimiyle okuduğunuz bir sınıf. Yazabileceğiniz bir adı yoktur, bu yüzden birini tutan bir değişken var ile bildirilmelidir ve tek bir metodun içinde kalan sonuçlara uyar.
OrderBy, ThenBy ve birkaç anahtara göre sıralama
Çıktı:
Ana 60
Ana 15
Ben 90
Ben 40
Chloe 25
Ben, Ana, Ben, Chloe, Ana
OrderBy kararlıdır: anahtarları eşit olan elemanlar orijinal sıralarında kalır. İkinci bir anahtar için ThenBy ya da ThenByDescending kullanın. İkinci bir OrderBy her şeyi kendi anahtarına göre yeniden sıralar ve ilk anahtarı yalnızca eşitlik bozucu olarak bırakır: ters öncelik. Sorgu sözdiziminde anahtarlar virgülle ayrılır: orderby o.Customer, o.Total descending.
List<T>.Sort'un aksine OrderBy kaynağa dokunmaz ve yeni bir dizi döndürür.
First, Single, Last ve OrDefault sürümleri
Bunlar bir dizi yerine tek bir eleman döndürür. Düz sürümler döndürecek bir şey olmadığında istisna fırlatır; OrDefault sürümleri tipin varsayılan değerini döndürür.
Çıktı:
Ana
Ben
Bea
True
First: InvalidOperationException
Single: InvalidOperationException
0
Boş bir dizide First'ten gelen istisna, "Sequence contains no elements" (ya da bir koşul hiçbir şeyle eşleşmediğinde "Sequence contains no matching element") mesajlı InvalidOperationException'dır; en çok aranan C# hatalarından biridir. "Hiç yok" normal bir sonuçsa FirstOrDefault kullanın ve null için kontrol edin.
Son satır değer tipi tuzağını gösterir: bir int dizisi için FirstOrDefault hiçbir şey eşleşmediğinde 0 döndürür ve bu gerçek bir 0'dan ayırt edilemez. Where ile filtreleyip önce Any() kontrol edin ya da .NET 6 ve sonrasında kendi varsayılanınızı verin: scores.FirstOrDefault(s => s > 100, -1).
Single "tam olarak bir" içindir: hiç yoksa ya da birden fazlaysa istisna fırlatır; bu da onu bir sorgu kadar bir doğrulama yapar.
Any, All, Count ve Contains
Çıktı:
True
True
True
3
True
True
Any() ilk eşleşmede durur, bu yüzden "bir şey var mı?" diye sormanın doğru yolu items.Any()'dir. Kaynak bir liste ya da dizi gibi bir koleksiyonsa items.Count() > 0 Count property'sini okur, ama bir sorguda ya da başka tembel bir dizide önce her elemanı dolaşır. Boş bir dizide All true döndürür, çünkü koşulu sağlamayan bir eleman yoktur.
Sum, Average, Min ve Max
Çıktı:
Total: 28.25
Items: 7
Priciest: 7.25
Average price: 4.92
0
Average: InvalidOperationException
Boş bir dizinin Sum'ı 0'dır, ama boş bir sayı dizisinin Average, Min ve Max'i InvalidOperationException fırlatır: mantıklı bir cevap yoktur. Any() ile koruyun ya da önce DefaultIfEmpty() kullanın: empty.DefaultIfEmpty(0).Average().
Distinct, Take ve Skip
Çıktı:
home, shop, cart
Page 1: 1 2 3 4 5 6 7 8 9 10
Page 2: 11 12 13 14 15 16 17 18 19 20
Page 3: 21 22 23
12, 15
Distinct her değerin ilk geçişini sırayla tutar. Skip(n).Take(m) standart sayfalama kalıbıdır ve TakeWhile/SkipWhile bir koşulu sağlamayan ilk elemanda durur ya da başlar. Enumerable.Range(start, count) dizi olmadan bir tamsayı dizisi üretir.
GroupBy
GroupBy elemanları bir anahtara göre kovalara ayırır. Her grubun bir Key'i vardır ve kendisi bir dizidir, bu yüzden onu toplayabilirsiniz.
Çıktı:
North: 3 sales, total 600
South: 2 sales, total 400
East: 1 sales, total 350
Top rep: Ana 400
North -> Ana/Chloe/Ana; South -> Ben/Eli; East -> Dev
Gruplar sıralı değil, anahtarlarının kaynakta ilk göründüğü sırayla çıkar (North, South, East); bunu istiyorsanız OrderBy(g => g.Key) ekleyin. Sorgu sözdiziminde group X by K her gruba neyin gireceğini seçer (burada yalnızca temsilcinin adı) ve into g sorgunun devam edebilmesi için gruba ad verir.
ToList, ToArray ve ToDictionary
To... metotları sorguyu çalıştırır ve sonuçları saklar.
Çıktı:
ben@x.com
2
ToDictionary: ArgumentException
İki eleman aynı anahtarı ürettiğinde ToDictionary, tıpkı Dictionary.Add gibi ArgumentException fırlatır. Tekrarlar bekleniyorsa önce gruplayın (wordCounts'un yaptığı gibi) ya da her anahtarı bir değerler dizisine eşleyen ToLookup'ı kullanın.
Ertelenmiş yürütme
Where, Select, OrderBy, GroupBy ve diğer operatörlerin çoğu bir sorgu nesnesi döndürür ve bir şey onu dolaşana kadar hiçbir iş yapmaz. Bunun görmeye değer iki sonucu vardır:
Çıktı:
25, 40, 99
converting 10
converting 25
converting 40
converting 99
Count: 4
converting 10
converting 25
converting 40
converting 99
Max: 9900
converting 10
converting 25
converting 40
converting 99
Cached: 4, 9900
İlk sorgu, sorgu yazıldıktan sonra eklendiği halde 99'u gördü: filtre string.Join onu dolaştığında çalıştı. İkinci sorgu dönüşümlerini iki kez yazdırdı, çünkü Count() ve Max() onu her biri sıfırdan dolaştı. Ucuz bir lambda ile bu yalnızca boşa harcanan iştir; lambda'nın içinde bir veritabanı sorgusu, bir dosya okuma ya da rastgele bir sayı olduğunda iki geçiş farklı veri döndürebilir. Bir sonucu birden fazla kez kullanacaksanız onu ToList() ya da ToArray() ile somutlaştırın.
Tek bir değer döndüren operatörler (Count, Sum, First, Any, Max) ve To... metotları hemen çalışır. Bu tembelliğin nasıl kurulduğu için IEnumerable ve yield sayfasına bakın.
Hızlı başvuru
| Operatör | Yaptığı | Döndürdüğü |
|---|---|---|
Where(x => cond) | Filtreler | Dizi (ertelenmiş) |
Select(x => expr) | Her birini dönüştürür | Dizi (ertelenmiş) |
SelectMany(x => seq) | İç içe dizileri düzleştirir | Dizi (ertelenmiş) |
OrderBy, ThenBy (+Descending) | Sıralar, kararlı | Dizi (ertelenmiş) |
GroupBy(x => key) | Anahtara göre kovalar | Gruplardan oluşan dizi (ertelenmiş) |
Distinct, Take, Skip | Tekrarları atar, sayfalar | Dizi (ertelenmiş) |
First, Single, Last | Tek eleman, yoksa istisna | Eleman |
FirstOrDefault vb. | Tek eleman ya da varsayılan | Eleman |
Any, All, Contains | Test eder | bool |
Count, Sum, Min, Max, Average | Toplar | Sayı |
ToList, ToArray, ToDictionary | Çalıştırır ve saklar | Koleksiyon |
Yaygın hatalar
- Boş olabilecek bir dizide
First(). "Sequence contains no elements" fırlatır;FirstOrDefaultkullanın ve kontrol edin. - İki
OrderByçağrısı. İkinci anahtar asıl anahtar olur;ThenBykullanın. - Bir sorguyu birkaç kez dolaşmak. İş tekrarlanır; bir kez
ToList()çağırın. - Bir sorgunun kaynağının anlık görüntüsünü almasını beklemek. Kaynağı yazıldığında değil, dolaşıldığında okur.
- Boş bir dizide
Average,Min,Max. İstisna fırlatırlar;Any()ya daDefaultIfEmptyile koruyun. - Eleman olup olmadığını test etmek için
Count() > 0.Any()ilkinde durur.
Sıkça Sorulan Sorular
C#'ta LINQ nedir?
LINQ (Language Integrated Query), System.Linq içinde Where, Select, OrderBy ve GroupBy gibi, herhangi bir IEnumerable<T> üzerinde çalışan bir extension metot kümesidir: diziler, listeler, dictionary'ler ve diğer sorguların sonuçları. C#'ta derleyicinin aynı metot çağrılarına çevirdiği bir sorgu sözdizimi de (from x in items where ... select ...) vardır.
LINQ'te Select ile Where arasındaki fark nedir?
Where filtreler: lambda'nın true döndürdüğü elemanları tutar ve onları değiştirmez. Select projeksiyon yapar: her elemanı bir property ya da yeni bir nesne gibi başka bir şeye dönüştürür ve sayıyı aynı tutar. Sık sık zincirlenirler: people.Where(p => p.Age >= 18).Select(p => p.Name).
First ile FirstOrDefault arasındaki fark nedir?
First() ilk elemanı (ya da bir koşul için ilk eşleşmeyi) döndürür ve hiç yoksa InvalidOperationException ("Sequence contains no elements" ya da "no matching element") fırlatır. FirstOrDefault() bunun yerine tipin varsayılan değerini döndürür: sınıflar için null, int için 0; bu yüzden sonucu kullanmadan önce kontrol edin.
LINQ ile iki alana göre nasıl sıralanır?
OrderBy'dan sonra ThenBy zincirleyin: orders.OrderBy(o => o.Customer).ThenByDescending(o => o.Total). OrderBy'ı iki kez çağırmak çalışmaz: ikinci çağrı tüm diziyi yeniden sıralar, bu yüzden onun anahtarı birincil olur ve ilk anahtar yalnızca eşitlikleri bozar; kastedilenin tersi.
LINQ'te GroupBy nasıl çalışır?
GroupBy(x => key) her farklı anahtar için bir grup döndürür. Her grup bir IGrouping<TKey, TElement>'tir: bir Key property'si vardır ve kendisi o anahtara sahip elemanlardan oluşan bir dizidir, bu yüzden üzerinde Count(), Sum() ya da Select çağırabilirsiniz. Gruplar anahtarlarının ilk göründüğü sırayla çıkar.
LINQ'te ertelenmiş yürütme nedir?
Çoğu LINQ operatörü çağırdığınızda çalışmaz; her dolaşıldığında (foreach, ToList(), Count() vb. ile) çalışan bir sorgu döndürür. Bu yüzden bir sorgu, tanımlandıktan sonra kaynağa yapılan değişiklikleri görür ve onu iki kez dolaşmak işi iki kez yapar. Bir kez çalıştırıp sonuçları tutmak için ToList() ya da ToArray() çağırın.