Zincirleme LINQ uzantı yöntemi çağrılarındaki 'let' anahtar kelimesine eşdeğer kod


192

C # derleyicileri sorgu anlama özelliklerini kullanarak aşağıdaki gibi kod yazabilirsiniz:

var names = new string[] { "Dog", "Cat", "Giraffe", "Monkey", "Tortoise" };
var result =
    from animalName in names
    let nameLength = animalName.Length
    where nameLength > 3
    orderby nameLength
    select animalName; 

Yukarıdaki sorgu ifadesinde, letanahtar kelime, değerin yinelenen çağrılar olmadan nereye ve sipariş işlemlerine iletilmesine izin verir animalName.Length.

Burada "let" anahtar kelimesinin ne yaptığını sağlayan eşdeğer LINQ uzantı yöntemi çağrısı nedir?


11
FYI, C # 3.0 spesifikasyonu, her sorgu anlama çeviri kuralını dayanılmaz ayrıntılarla açıklamaktadır.
Eric Lippert

17
ve spec ağır gidiş buluyor olanlar için, Jon Skeet derinliği C # de kapsar ;-p
Marc Gravell

C # Dil Spesifikasyonları, içeriği arama motorları tarafından endekslenmeyen ve çevrimiçi olarak ne bağlanabilir ne de göz atılabilir olan indirilebilir Word belgeleridir. Spesifikasyonlar çevrimiçi olarak mevcut olsaydı çok yardımcı olurdu.
Olivier Jacot-Descombes

Yanıtlar:


250

Let'nin kendi operasyonu yok; domuzcuk geri çekiliyor Select. Mevcut bir dll ayırmak için "reflektör" kullanıyorsanız bunu görebilirsiniz.

şöyle bir şey olacak :

var result = names
        .Select(animalName => new { nameLength = animalName.Length, animalName})
        .Where(x=>x.nameLength > 3)
        .OrderBy(x=>x.nameLength)
        .Select(x=>x.animalName);

4
Woah, böyle yeni operatörü kullanarak otomatik kapsülleme yapabileceğinizi bilmiyordum.
David Pfeffer

19
Ayrıca oluşturulan kodunu görmek için LINQPad sonucu bölmesinde küçük "lambda" düğmesini kullanabilirsiniz eğer bir Queryable ile başlar. Başka bir deyişle, ilk satırınızı var names = new string [] {"Dog", ...} olarak değiştirirseniz .AsQueryable (); sonra her şeyi LinqPad'de çalıştırın, küçük lambda düğmesine tıklayın, oluşturulan kodun Marc'ın cevabına neredeyse aynı olduğunu göreceksiniz.
Reb.Cabin

3
.Dump()Ortaya çıkan lambda görmek için LinqPad uzatma yöntemini kullanmak gerekiyordu .
justanotherdev

88

Burada iyi bir makale var

Esasen letanonim bir grup oluşturur. Şuna eşittir:

var result = names.Select(
  animal => new { animal = animal, nameLength = animal.Length })
.Where(x => x.nameLength > 3)
.OrderBy(y => y.nameLength)
.Select(z => z.animal);

Yukarıdaki makaleyi alıntıladımit seems prudent to recommend against using the let keyword in cases where you do not need to transform a variable
JB. Monica ile.

Daha da alıntı yapıyorum:This could be considered a micro-optimisation
Monsignor

7

Ayrıca System.Interactive içinde bir .Let uzatma yöntemi vardır, ancak amacı akıcı bir ifadede 'in-line' olarak değerlendirilecek lambda ifadesini tanıtmaktır. Örneğin, her yürütüldüğünde yeni rasgele sayılar oluşturan aşağıdaki ifadeyi (LinqPad'de diyelim) düşünün:

var seq = EnumerableEx.Generate(
    new Random(),
    _ => true,
    _ => _,
    x => x.Next());

Her seferinde yeni rastgele örneklerin göründüğünü görmek için aşağıdakileri göz önünde bulundurun

seq.Zip(seq, Tuple.Create).Take(3).Dump();

sol ve sağın farklı olduğu çiftler üretir. Sol ve sağın her zaman aynı olduğu çiftler üretmek için aşağıdakine benzer bir şey yapın:

seq.Take(3).ToList().Let(xs => xs.Zip(xs, Tuple.Create)).Dump(); 

Lambda ifadelerini doğrudan çağırabilirsek,

(xs => xs.Zip(xs, Tuple.Create))(seq.Take(3).ToList()).Dump();

Ama lambda ifadelerini yöntemmiş gibi çağıramayız.


1

LINQ uzantı yöntemi çağrılarındaki 'let' anahtar kelimesine eşdeğer kod hakkında

yukarıdaki yorum artık geçerli değil

var x = new List<int> { 2, 3, 4, 5, 6 }.AsQueryable();
(from val in x
let val1 = val
let val2 = val + 1
where val2 > val1
select val
).Dump();

üretir

System.Collections.Generic.List`1[System.Int32]
.Select(
  val =>
     new
     {
         val = val,
         val1 = val
     }
)
.Select(
  temp0 =>
     new
     {
         temp0 = temp0,
         val2 = (temp0.val + 1)
     }
)
.Where(temp1 => (temp1.val2 > temp1.temp0.val1))
.Select(temp1 => temp1.temp0.val)

letşimdi çoklu optimize edildi

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.