2010-09-07 27 views
6

Tôi có một đoạn mã cho một số logic xác nhận, mà trong khái quát hóa cho đi như thế này:LINQ hoặc foreach - phong cách/dễ đọc và tốc độ

private bool AllItemsAreSatisfactoryV1(IEnumerable<Source> collection) 
{ 
    foreach(var foo in collection) 
    { 
     Target target = SomeFancyLookup(foo); 
     if (!target.Satisfactory) 
     { 
      return false; 
     } 
    } 
    return true; 
} 

này hoạt động, là khá dễ hiểu, và có đầu tối ưu hóa. Đó là, tuy nhiên, khá tiết. Mục đích chính của câu hỏi này là những gì được coi là có thể đọc được và phong cách tốt. Tôi cũng quan tâm đến buổi biểu diễn; Tôi tin tưởng rằng sớm {tối ưu hóa, bi quan} là gốc rễ của tất cả các ác và cố gắng tránh tối ưu hóa vi mô cũng như giới thiệu các nút cổ chai.

Tôi khá mới đối với LINQ, vì vậy tôi muốn một số nhận xét về hai phiên bản thay thế mà tôi đã đưa ra, cũng như bất kỳ đề xuất nào khác. dễ đọc.

private bool AllItemsAreSatisfactoryV2(IEnumerable<Source> collection) 
{ 
    return null == 
     (from foo in collection 
     where !(SomeFancyLookup(foo).Satisfactory) 
     select foo).First(); 
} 

private bool AllItemsAreSatisfactoryV3(IEnumerable<Source> collection) 
{ 
    return !collection.Any(foo => !SomeFancyLookup(foo).Satisfactory); 
} 

Tôi không tin rằng V2 cung cấp nhiều hơn V1 về khả năng đọc, ngay cả khi ngắn hơn. Tôi tìm thấy V3 để rõ ràng & súc tích, nhưng tôi không quá thích phần Method().Property; tất nhiên tôi có thể biến lambda thành một đại biểu đầy đủ, nhưng sau đó nó mất đi sự sang trọng một dòng.

Những gì tôi muốn bình luận trên là:

  1. Style - bao giờ nên chủ quan, nhưng những gì bạn cảm thấy là có thể đọc được?
  2. Hiệu suất - có bất kỳ điều gì trong số này không xác định không? Theo như tôi hiểu, cả ba phương pháp đều nên sớm.
  3. Khả năng gỡ lỗi - bất kỳ điều gì cần xem xét?
  4. Giải pháp thay thế - mọi thứ đều diễn ra.

Cảm ơn trước :)

+2

Khi đọc LINQ, tôi không bao giờ có thể dễ dàng hiểu được cách "ngôn ngữ tự nhiên" (tất cả các 'từ x trong xs chọn ...'). Phiên bản 'xs.Select (x => ...)' luôn có vẻ rõ ràng hơn và có ý nghĩa hơn với tôi (nhưng đó chỉ là tôi). V3 là dễ đọc nhất đối với tôi. –

+0

@Callum Rogers: Tôi cảm thấy khá giống nhau; những người làm rất nhiều SQL có thể cảm thấy khác nhau, mặc dù :) – snemarch

Trả lời

12

Tôi nghĩ All sẽ được rõ ràng hơn:

private bool AllItemsAreSatisfactoryV1(IEnumerable<Source> collection) 
{ 
    return collection.Select(f => SomeFancyLookup(f)).All(t => t.Satisfactory); 
} 

tôi nghĩ rằng nó không sử dụng LINQ ở đây sẽ gây ra vấn đề hiệu suất trên một vòng lặp foreach thường xuyên, mặc dù nó sẽ đơn giản để thay đổi nếu nó đã làm.

+0

Đồng ý - không cần phải phủ định, và nó vẫn thoát ra sớm nếu nó tìm thấy một mục không đạt yêu cầu. –

+0

Trong .NET 4, bạn có thể đơn giản hóa nó hơn nữa: 'return collection.Select (SomeFancyLookup) .All (t => t.Satisfactory);' –

+0

@Joel - Cú pháp tương tự là hợp pháp trong 3.5; SomeFancyLookup trở thành một đại biểu có chữ ký phương thức đã biết. – KeithS

1

Cá nhân tôi không có vấn đề gì với kiểu V3, và đó là lựa chọn đầu tiên của tôi. Về cơ bản, bạn đang xem xét danh sách cho bất kỳ ai có tra cứu không thỏa đáng. V2 rất khó để nắm bắt được ý định, và ở dạng hiện tại của nó sẽ ném một ngoại lệ (First() yêu cầu nguồn IEnumerable không được để trống, tôi nghĩ rằng bạn đang tìm kiếm FirstOrDefault()). Tại sao không chỉ tack Any() vào cuối thay vì so sánh kết quả từ danh sách thành null?

V1 là tốt, nếu có chút khó khăn, và có lẽ là cách dễ nhất để gỡ lỗi, vì tôi đã thấy gỡ lỗi lambdas đôi khi hơi bất thường. Bạn có thể loại bỏ các dấu ngoặc bên trong để mất một số khoảng trắng mà không bị mất khả năng đọc.

Thực sự, cả ba sẽ đun sôi thành các mã opcode rất giống nhau; lặp qua bộ sưu tập, gọi SomeFancyLookup() và kiểm tra thuộc tính của giá trị trả về của nó; thoát ra khỏi thất bại đầu tiên. Bất kỳ() "ẩn" một thuật toán foreach rất giống nhau. Sự khác biệt giữa V1 và tất cả những thứ khác là việc sử dụng biến được đặt tên, mà MIGHT kém hiệu quả hơn một chút, nhưng bạn có một tham chiếu đến Target trong cả ba trường hợp, vì vậy tôi nghi ngờ nó là quan trọng, nếu có sự khác biệt.

+0

"Tại sao không chỉ tack Bất kỳ() vào cuối" - d'oh! Cảm ơn bạn đã cảnh báo ngoại lệ. Mã IL rất giống nhau thực sự được tạo ra cho hai phiên bản LINQ, với phiên bản "ngôn ngữ tự nhiên" có thêm một cuộc gọi. – snemarch

Các vấn đề liên quan