2008-12-02 21 views
25

Bạn có loại mặc định mà bạn muốn sử dụng trong các giao dịch của mình với kết quả truy vấn LINQ không?Bạn có ToList() không?

Theo mặc định LINQ sẽ trả lại IEnumerable<> hoặc có thể là IOrderedEnumerable<>. Chúng tôi nhận thấy rằng List<> thường hữu ích hơn đối với chúng tôi, vì vậy, chúng tôi đã áp dụng thói quen ToList() truy vấn của chúng tôi hầu hết thời gian và chắc chắn sử dụng List<> trong đối số và giá trị trả về của chúng tôi.

Ngoại lệ duy nhất cho điều này đã nằm trong LINQ to SQL trong đó gọi .ToList() sẽ liệt kê số IEnumerable sớm.

Chúng tôi cũng đang sử dụng rộng rãi WCF, loại bộ sưu tập mặc định là System.Array. Chúng tôi luôn thay đổi điều này thành System.Collections.Generic.List trong hộp thoại Cài đặt tham chiếu dịch vụ trong VS2008 để phù hợp với phần còn lại của codebase của chúng tôi.

Bạn làm nghề gì?

Trả lời

23

ToListluôn luôn đánh giá chuỗi ngay lập tức - không chỉ trong LINQ to SQL. Nếu bạn muốn điều đó, điều đó tốt - nhưng nó không phải lúc nào cũng thích hợp.

Cá nhân tôi sẽ cố gắng tránh tuyên bố rằng bạn trả lại trực tiếp List<T> - thường là IList<T> phù hợp hơn và cho phép bạn thay đổi sang triển khai khác sau này. Tất nhiên, có một số hoạt động mà chỉ được quy định trên List<T> chính nó ... loại quyết định này luôn luôn là khó khăn.

EDIT: (Tôi đã đưa điều này vào một bình luận, nhưng nó sẽ quá cồng kềnh.) Thực thi hoãn lại cho phép bạn xử lý các nguồn dữ liệu quá lớn để vừa với bộ nhớ. Chẳng hạn, nếu bạn đang xử lý các tệp nhật ký - chuyển đổi chúng từ định dạng này sang định dạng khác, tải chúng lên cơ sở dữ liệu, thực hiện một số thống kê hoặc thứ gì đó tương tự - bạn có thể xử lý một lượng dữ liệu tùy ý bằng cách truyền trực tuyến , nhưng bạn thực sự không muốn hút mọi thứ vào bộ nhớ. Điều này có thể không phải là một mối quan tâm cho ứng dụng cụ thể của bạn, nhưng nó là một cái gì đó để ghi nhớ.

+1

Đồng ý rằng ToList đánh giá ngay lập tức. Suy nghĩ của chúng tôi là trong LINQtoSQL, điều này có thể có tác động đến hiệu suất (đặc biệt là nếu chúng ta kết hợp với nhau một vài biểu thức LINQ), nhưng khi chúng ta đang ở trong bộ nhớ, bất kỳ hiệu suất nào cũng có thể bỏ qua - và tính nhất quán của con người quan trọng. –

+3

Có sự khác biệt đáng kể ngoài hiệu suất. Đặc biệt, nếu có bất kỳ điều gì về truy vấn (ví dụ: dữ liệu trong nguồn) thay đổi, thì việc thực thi hoãn lại sẽ cung cấp cho bạn một câu trả lời khác. Đôi khi đó là những gì bạn muốn, đôi khi nó không phải là. –

2

Điều đó tùy thuộc vào việc bạn cần sửa đổi bộ sưu tập. Tôi thích sử dụng một mảng khi tôi biết rằng không ai sẽ thêm/xóa các mục. Tôi sử dụng một danh sách khi tôi cần sắp xếp/thêm/xóa các mục. Nhưng, thông thường tôi chỉ để nó như IEnumerable miễn là tôi có thể.

16

Chúng tôi có cùng một kịch bản - WCF liên lạc với máy chủ, máy chủ sử dụng LINQtoSQL.

Chúng tôi sử dụng. ToArray() khi yêu cầu đối tượng từ máy chủ, bởi vì đó là "bất hợp pháp" để khách hàng thay đổi danh sách. (Có nghĩa là, không có mục đích để hỗ trợ ".Thêm", ".Xóa", v.v.).

Mặc dù vẫn ở trên máy chủ, tuy nhiên, tôi khuyên bạn nên để mặc định là mặc định (không phải IEnumerable, mà là IQueryable). Bằng cách này, nếu bạn muốn lọc nhiều hơn dựa trên một số tiêu chí, lọc là STILL ở phía SQL cho đến khi được đánh giá.

Đây là một điểm rất quan trọng vì nó có nghĩa là đạt được hiệu suất đáng kinh ngạc hoặc thua lỗ tùy thuộc vào những gì bạn làm.

VÍ DỤ:

// This is just an example... imagine this is on the server only. It's the 
// basic method that gets the list of clients. 
private IEnumerable<Client> GetClients() 
{ 
    var result = MyDataContext.Clients; 

    return result.AsEnumerable(); 
} 

// This method here is actually called by the user... 
public Client[] GetClientsForLoggedInUser() 
{ 
    var clients = GetClients().Where(client=> client.Owner == currentUser); 

    return clients.ToArray(); 
} 

Bạn có thấy những gì đang xảy ra ở đó?Phương thức "GetClients" sẽ buộc tải xuống ALL 'clients' từ cơ sở dữ liệu ... Mệnh đề Where sẽ xảy ra trong phương thức GetClientsForLoogedInUser để lọc nó xuống.

Bây giờ, hãy chú ý những thay đổi nhỏ:

private IQueryable<Client> GetClients() 
{ 
    var result = MyDataContext.Clients; 

    return result.AsQueryable(); 
} 

Bây giờ, việc đánh giá thực tế sẽ không xảy ra cho đến khi ".ToArray" được gọi là ... và SQL sẽ thực hiện lọc. Tốt hơn nhiều!

+0

Điểm của bạn là một điểm rất khác biệt. Hầu hết mọi người dường như bỏ lỡ nó mặc dù. Tôi thấy những ví dụ thực sự tồi tệ như thế này được sử dụng mọi lúc. Mọi người không dừng lại để suy nghĩ về những gì mà diễn viên sẽ làm khi thực hiện. –

+0

Câu trả lời hay, quá rõ ràng. Cảm ơn rất nhiều – MegaMind

7

Trong trường hợp LINQ-to-Objects, trả lại List<T> từ một hàm không đẹp bằng cách trả lại IList<T>, như THE VENERABLE SKEET chỉ ra. Nhưng thường thì bạn vẫn có thể làm tốt hơn thế. Nếu điều bạn đang quay trở lại phải là bất biến, thì IList là một lựa chọn tồi vì nó mời người gọi thêm hoặc xóa mọi thứ. Ví dụ: đôi khi bạn có phương thức hoặc thuộc tính trả về kết quả của truy vấn LINQ hoặc sử dụng yield return để tạo một danh sách, và sau đó bạn nhận ra rằng tốt hơn nên làm điều đó lần đầu tiên bạn được gọi , lưu vào bộ nhớ cache kết quả theo số List<T> và trả về phiên bản được lưu trong bộ nhớ cache sau đó. Đó là khi trả lại IList có thể là một ý tưởng tồi, bởi vì người gọi có thể sửa đổi danh sách cho mục đích riêng của họ, sau đó sẽ làm hỏng bộ nhớ cache của bạn, làm cho các thay đổi của họ hiển thị đối với tất cả người gọi khác.

Tốt hơn để trả lại IEnumerable<T>, vì vậy tất cả những gì họ có là chuyển tiếp lặp lại. Và nếu người gọi muốn truy cập ngẫu nhiên nhanh, nghĩa là họ muốn họ có thể sử dụng [] để truy cập theo chỉ mục, họ có thể sử dụng ElementAt, mà LINQ định nghĩa sao cho nó lặng lẽ ngửi cho IList và sử dụng nếu có, và nếu không thì tra cứu tuyến tính.

Một điều tôi đã sử dụng ToList là khi tôi có một hệ thống phức tạp các biểu thức LINQ được trộn lẫn với toán tử tùy chỉnh sử dụng yield return để lọc hoặc chuyển đổi danh sách. Bước qua trong trình gỡ rối có thể trở nên khó hiểu khi nó nhảy xung quanh làm việc đánh giá lười biếng, vì vậy đôi khi tôi tạm thời thêm một ToList() vào một vài nơi để tôi có thể dễ dàng thực hiện theo đường dẫn thực hiện. (Mặc dù nếu những thứ bạn đang thực hiện có tác dụng phụ, điều này có thể thay đổi ý nghĩa của chương trình.)

+0

Cũng lưu ý rằng có một chuyển động trong .NET 4.5 để thực sự cung cấp phiên bản chỉ đọc các giao diện phổ biến mà chúng tôi đã phát triển để yêu như IList với IReadOnlyList mới. http://msdn.microsoft.com/en-us/library/hh192385.aspx – jpierson

2

Nếu bạn không cần thêm các tính năng của Danh sách <>, tại sao không chỉ với IQueryable <>? !?!?! Mẫu số chung thấp nhất là giải pháp tốt nhất (đặc biệt là khi bạn nhìn thấy câu trả lời của Timothy).

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