2012-04-09 15 views
6

Nếu tôi đang cố gắng lọc kết quả ở nhiều cấp độ khác nhau của đồ thị đối tượng IEnumerable<T>, có cách nào ưu tiên là chuỗi các phương pháp mở rộng để thực hiện việc này không?Cách ưa thích (có thể thực hiện và có thể đọc được) của chuỗi các phương pháp mở rộng IEnumerable <T> là gì?

Tôi đang mở cho bất kỳ phương pháp tiện ích mở rộng nào và sử dụng lambda, nhưng tôi không muốn sử dụng cú pháp LINQ để duy trì tính nhất quán với phần còn lại của codebase.

Có tốt hơn không khi đẩy bộ lọc đến selector của phương pháp SelectMany() hoặc chỉ để kết nối phương thức Where() khác? Hoặc là có một giải pháp tốt hơn?

Tôi sẽ làm cách nào để xác định tùy chọn tốt nhất? Trong trường hợp thử nghiệm này, mọi thứ đều có sẵn trong bộ nhớ. Rõ ràng cả hai mẫu dưới đây hiện đang sản xuất cùng một kết quả chính xác; Tôi chỉ tìm kiếm một lý do nào đó hoặc một lý do khác (hoặc một tùy chọn khác) sẽ được ưu tiên hơn.

public class Test 
{ 
    // I want the first chapter of a book that's exactly 42 pages, written by 
    // an author whose name is Adams, from a library in London. 
    public Chapter TestingIEnumerableTExtensionMethods() 
    { 
     List<Library> libraries = GetLibraries(); 

     Chapter chapter = libraries 
      .Where(lib => lib.City == "London") 
      .SelectMany(lib => lib.Books) 
      .Where(b => b.Author == "Adams") 
      .SelectMany(b => b.Chapters) 
      .First(c => c.NumberOfPages == 42); 

     Chapter chapter2 = libraries 
      .Where(lib => lib.City == "London") 
      .SelectMany(lib => lib.Books.Where(b => b.Author == "Adams")) 
      .SelectMany(b => b.Chapters.Where(c => c.NumberOfPages == 42)) 
      .First(); 
    } 

Và đây là đồ thị đối tượng mẫu:

public class Library 
{ 
    public string Name { get; set; } 
    public string City { get; set; } 
    public List<Book> Books { get; set; } 
} 

public class Book 
{ 
    public string Name { get; set; } 
    public string Author { get; set; } 
    public List<Chapter> Chapters { get; set; } 
} 

public class Chapter 
{ 
    public string Name { get; set; } 
    public int NumberOfPages { get; set; } 
} 
+1

Khả năng đọc có vẻ như bằng nhau. Hiệu suất phụ thuộc vào việc đây là linq đối với các đối tượng hay linq với bất kỳ thứ gì khác; tại sao bạn không đo lường nó và xem? – phoog

+0

là các truy vấn của bạn luôn dưới dạng 'thư viện => sách => chương' - hoặc bạn có thể có nhiều mối quan hệ phức tạp hơn (tôi đoán đây chỉ là mô hình thử nghiệm) – NSGaga

+0

@NSGaga Chúng luôn ở dạng thứ bậc, nhưng bạn chính xác rằng đó chỉ là một mô hình thử nghiệm để giúp người đọc dễ hiểu hơn. Về mặt kỹ thuật, tôi đang làm việc với các cấu trúc EDI (ANSI X12), vì vậy các tệp, ISA, GS và các phân đoạn ST. –

Trả lời

1

Nó phụ thuộc vào cách thức cơ bản các công trình cung cấp LINQ. Đối với LINQ to Objects, cả trong trường hợp này sẽ yêu cầu cùng một lượng công việc, nhiều hơn hoặc ít hơn. Nhưng đó là ví dụ đơn giản nhất (đơn giản nhất), vượt ra ngoài khó mà nói được.

2

Tôi đoán biểu thức đầu tiên bạn sẽ có một chút nhưng không đáng kể nhanh hơn. Để thực sự xác định xem cái này hay cái kia nhanh hơn, bạn sẽ cần phải thời gian cho chúng, với một hồ sơ hoặc Đồng hồ bấm giờ.

Khả năng đọc dường như không bị ảnh hưởng mạnh theo cách nào. Tôi thích cách tiếp cận đầu tiên, vì nó có ít cấp độ làm tổ hơn. Tất cả phụ thuộc vào sở thích cá nhân của bạn.

+0

Vâng, cái đầu tiên sẽ nhanh hơn vì bạn không tạo ra một nơi lặp cho mỗi mục. – usr

3

Tùy chọn nào tốt nhất có thể thay đổi dựa trên triển khai LINQ bạn đang sử dụng. LinqToSql sẽ hoạt động khác với bộ lọc trong bộ nhớ. Thứ tự của các mệnh đề sẽ tác động đến hiệu suất phụ thuộc vào dữ liệu nào được sử dụng, vì việc triển khai ngây thơ sẽ lọc nhiều bản ghi trước đó trong chuỗi có nghĩa là ít công việc hơn cho các phương thức sau. Đối với hai ví dụ của bạn, tôi đoán rằng sự khác biệt hiệu suất là không đáng kể và sẽ ưu tiên đầu tiên vì nó cho phép sửa đổi dễ dàng hơn của từng mệnh đề độc lập với các điều khoản khác.

Để xác định tùy chọn tốt nhất, nó giống như bất cứ điều gì khác: đo lường.

0

này có thể cung cấp cho bạn một góc độ khác nhau, mặc dù nó là nhiều hơn một vấn đề của phong cách ...
đôi khi tôi thấy mình làm một cái gì đó như thế này ...

return libraries.Filter(
     l => l.City == "", 
     l => l.Books, 
     b => b.Author == "Adams", 
     b => b.Chapters, 
     c => c.NumberOfPages == 42 
     ); 

... nơi bạn có thể đoán những gì các extensiion là, một cái gì đó giống như ...

public static IEnumerable<TC> Filter<TL, TB, TC>(this IEnumerable<TL> list, 
    Func<TL, bool> whereLs, 
    Func<TL, IEnumerable<TB>> selectBs, 
    Func<TB, bool> whereBs, 
    Func<TB, IEnumerable<TC>> selectCs, 
    Func<TC, bool> whereCs 
    ) 
{ 
    return list 
     .Where(whereLs) 
     .SelectMany(selectBs) 
     .Where(whereBs) 
     .SelectMany(selectCs) 
     .Where(whereCs); 
} 

... hay ....

...  
{ 
    return list 
     .Where(whereLs) 
     .SelectMany(l => selectBs(l).Where(whereBs)) 
     .SelectMany(b => selectCs(b).Where(whereCs)); 
} 

Và các kết hợp/tùy chọn rất nhiều, tùy thuộc vào những gì bạn có, cách bạn muốn có mã của bạn '(trừu tượng hóa nó một số chi tiết hơn hoặc' chụp ',' parametrize 'ví dụ PerCityAuthorPages(_city, _author, _numPages); v.v.)

...về cơ bản, tôi không thích có tất cả 'Where', 'Select'-s vv và với tôi không phải là có thể đọc được (hoặc). Trong khi với 'hình thức ngắn' nó khá rõ ràng đó là, ở đâu, chọn vv và nó rất nhiều 'ngắn tay' và trong ký tự ít hơn nhiều.

Ngoài ra, bạn có thể Deffer quyết định về đâu/Chọn kết hợp cho sau này (làm cái này hay cái khác dựa trên nhu cầu, nhà cung cấp)

Và @Telastyn là hoàn toàn đúng, các nhà cung cấp LINQ, ví dụ nếu bạn xem xét một số mã triển khai,
với tất cả các biểu thức giảm, v.v.
là khá không xác định (nghĩa là từ nhà cung cấp đến nhà cung cấp) theo cách họ có thể lập bản đồ. SQL
mặc dù điều này nên ánh xạ giống nhau trong hầu hết những gì tôi nghĩ.