รหัสเทียบเท่ากับคำสำคัญ 'ปล่อย' ในการเรียกใช้เมธอดส่วนขยาย LINQ ที่ถูกล่ามโซ่


192

ด้วยการใช้คุณสมบัติการทำความเข้าใจแบบสอบถามคอมไพเลอร์ C # คุณสามารถเขียนโค้ดดังนี้:

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; 

ในการแสดงออกของแบบสอบถามข้างต้นletคำหลักที่ช่วยให้คุ้มค่าที่จะส่งผ่านไปข้างหน้าเพื่อที่และ orderby animalName.Lengthการดำเนินงานโดยไม่ต้องโทรซ้ำไป

ชุดของวิธีการขยาย LINQ ที่เทียบเท่าที่เรียกว่าบรรลุคำหลัก "ให้" ทำอะไรที่นี่?


11
FYI ข้อกำหนด C # 3.0 อธิบายกฎการแปลความเข้าใจแบบสอบถามทั้งหมดในรายละเอียดที่น่ายินดี
Eric Lippert

17
และสำหรับผู้ที่พบว่าสเปคหนักไปจอน Skeet ของ C # ในความลึกครอบคลุมมัน ;-P เกินไป
Marc Gravell

ข้อมูลจำเพาะภาษา C # เป็นเอกสาร Word ที่สามารถดาวน์โหลดได้ซึ่งมีเนื้อหาที่ไม่ได้จัดทำดัชนีโดยเครื่องมือค้นหาและไม่สามารถลิงก์หรือเรียกดูออนไลน์ได้ มันจะเป็นความช่วยเหลือที่ดีมากหากมีข้อมูลจำเพาะทางออนไลน์
Olivier Jacot-Descombes

คำตอบ:


250

ให้ไม่มีการดำเนินงานของตัวเอง Selectมันลูกหมูหลังออกจาก คุณสามารถดูสิ่งนี้หากคุณใช้ "reflector" เพื่อดึง dll ที่มีอยู่ออกจากกัน

มันจะเป็นสิ่งที่ชอบ:

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

4
ว้าวฉันไม่รู้ว่าคุณสามารถรวบรวมข้อมูลอัตโนมัติโดยใช้ตัวดำเนินการใหม่แบบนั้น
David Pfeffer

19
คุณสามารถใช้ปุ่ม "แลมบ์ดา" เล็ก ๆ ในบานหน้าต่างผลลัพธ์ของ LinqPad เพื่อดูรหัสที่สร้างขึ้นหากคุณเริ่มต้นด้วย Queryable กล่าวอีกนัยหนึ่งถ้าคุณเปลี่ยนบรรทัดแรกเป็น var names = new string [] {"Dog", ... } .AsQueryable (); จากนั้นเรียกใช้ทุกสิ่งใน LinqPad คลิกปุ่มแลมบ์ดาเล็ก ๆ คุณจะเห็นรหัสที่สร้างขึ้นเหมือนกับคำตอบของ Marc
Reb.Cabin

3
ฉันจำเป็นต้องใช้.Dump()วิธีการขยายใน LinqPad เพื่อดูแลมบ์ดาที่เกิดขึ้น
justanotherdev

88

มีบทความที่ดีอยู่ที่นี่

เป็นหลักletสร้าง tuple ไม่ระบุชื่อ มันเทียบเท่ากับ:

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

ฉันพูดบทความข้างต้นit seems prudent to recommend against using the let keyword in cases where you do not need to transform a variable
JB กับโมนิก้า

ฉันพูดมันเพิ่มเติม:This could be considered a micro-optimisation
พระคุณเจ้า

7

นอกจากนี้ยังมีวิธีการส่วนขยาย. Let.Interactive แต่จุดประสงค์ของมันคือการแนะนำการแสดงออกแลมบ์ดาที่จะได้รับการประเมิน 'ในบรรทัด' ในการแสดงออกอย่างคล่องแคล่ว ตัวอย่างเช่นพิจารณา (ใน LinqPad พูด) นิพจน์ต่อไปนี้ที่สร้างหมายเลขสุ่มใหม่ทุกครั้งที่เรียกใช้:

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

หากต้องการดูตัวอย่างสุ่มใหม่ปรากฏขึ้นทุกครั้งให้พิจารณาสิ่งต่อไปนี้

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

ซึ่งสร้างคู่ที่ซ้ายและขวาแตกต่างกัน หากต้องการสร้างคู่ที่ซ้ายและขวาเหมือนกันเสมอทำสิ่งต่อไปนี้:

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

หากเราสามารถเรียกการแสดงออกแลมบ์ดาโดยตรงเราอาจเขียน

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

แต่เราไม่สามารถเรียกการแสดงออกแลมบ์ดาราวกับว่ามันเป็นวิธีการ


1

เกี่ยวกับรหัสเทียบเท่ากับคำหลัก 'ปล่อย' ในการเรียกวิธีการขยาย LINQ ที่ถูกล่ามโซ่

ความคิดเห็นด้านบนไม่ถูกต้อง

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();

ผลิต

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มีการเพิ่มประสิทธิภาพหลายรายการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.