Mã tương đương với từ khóa 'let' trong các cuộc gọi phương thức mở rộng LINQ


191

Sử dụng các tính năng hiểu các trình biên dịch C #, bạn có thể viết mã như:

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; 

Trong biểu thức truy vấn ở trên, lettừ khóa cho phép một giá trị được chuyển tiếp đến các hoạt động ở đâu và thứ tự mà không có các cuộc gọi trùng lặp đến animalName.Length.

Tập hợp các lệnh gọi phương thức mở rộng LINQ tương đương đạt được từ khóa "let" nào ở đây?


11
FYI, đặc tả C # 3.0 giải thích mọi quy tắc dịch hiểu toàn diện truy vấn một cách chi tiết.
Eric Lippert

17
và đối với những người tìm thấy thông số kỹ thuật nặng nề, C # in Depth của Jon Skeet cũng bao gồm nó ;-p
Marc Gravell

Thông số kỹ thuật ngôn ngữ C # là các tài liệu Word có thể tải xuống có nội dung không được công cụ tìm kiếm lập chỉ mục và không thể liên kết cũng như không thể duyệt trực tuyến. Nó sẽ là một trợ giúp tuyệt vời nếu các thông số kỹ thuật có sẵn trực tuyến.
Olivier Jacot-Descombes

Câu trả lời:


249

Chúng ta đừng có hoạt động riêng của nó; nó cõng ra Select. Bạn có thể thấy điều này nếu bạn sử dụng "gương phản xạ" để tách ra một dll hiện có.

nó sẽ là một cái gì đó như:

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

4
Ái chà, tôi không biết bạn có thể tự động đóng gói bằng cách sử dụng toán tử mới như thế.
David Pfeffer

19
Bạn cũng có thể sử dụng nút "lambda" nhỏ trong khung kết quả của LinqPad để xem mã được tạo nếu bạn bắt đầu với Truy vấn. Nói cách khác, nếu bạn thay đổi dòng đầu tiên của mình thành var name = new string [] {"Dog", ...} .AsQueryable (); sau đó chạy toàn bộ trong LinqPad, nhấp vào nút lambda nhỏ, bạn sẽ thấy mã được tạo gần như giống hệt với câu trả lời của Marc.
Reb.Cabin

3
Tôi cần sử dụng .Dump()phương thức mở rộng trong LinqPad để xem lambda kết quả.
justanotherdev

88

Có một bài viết hay ở đây

Về cơ bản lettạo ra một tuple ẩn danh. Nó tương đương với:

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

Tôi trích dẫn bài viết trênit seems prudent to recommend against using the let keyword in cases where you do not need to transform a variable
JB. Với Monica.

Tôi xin trích dẫn thêm:This could be considered a micro-optimisation
Đức ông

7

Ngoài ra còn có một phương thức mở rộng .Let trong System.Interactive, nhưng mục đích của nó là giới thiệu một biểu thức lambda để được đánh giá 'nội tuyến' trong một biểu thức lưu loát. Chẳng hạn, hãy xem xét (trong LinqPad, giả sử) biểu thức sau đây tạo ra các số ngẫu nhiên mới mỗi khi nó được thực thi:

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

Để thấy rằng các mẫu ngẫu nhiên mới xuất hiện mỗi lần, hãy xem xét những điều sau đây

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

tạo ra các cặp trong đó trái và phải khác nhau. Để tạo ra các cặp trong đó bên trái và bên phải luôn giống nhau, hãy làm như sau:

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

Nếu chúng ta có thể gọi trực tiếp biểu thức lambda, chúng ta có thể viết

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

Nhưng chúng ta không thể gọi các biểu thức lambda như thể chúng là các phương thức.


1

trong khoảng Mã tương đương với từ khóa 'cho phép' trong các cuộc gọi phương thức mở rộng LINQ

nhận xét trên không còn giá trị

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

sản xuất

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)

vì vậy nhiều letđược tối ưu hóa ngay bây giờ

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.