2009-03-25 26 views
8

Hãy tưởng tượng tôi có một lớp SearchService có một phương pháp để tìm kiếm tất cả các xe bắt đầu bằng một chuỗi nhất định;Dịch vụ của tôi nên trở về giao diện nào? IQueryable, IList, IEnumerable?

public static class Searcher{ 
    public IAnInterface<Car> CarsStartingWith(string startWith){ 
     //magic 
    } 
} 

Dịch vụ của tôi nên sử dụng giao diện nào?
IQueryable có thể hiển thị giao diện tốt đẹp trong phần còn lại của ứng dụng của tôi.
IEnumerable có khía cạnh lười biếng đi kèm với nó.
IList chỉ là thực tế nhất.

Tôi muốn có tất cả các dịch vụ của mình trả về cùng một giao diện để nhất quán làm cho toàn bộ mọi thứ trở nên dễ dàng hơn nhiều.
ICollection có lẽ có thể là một lựa chọn quá, nhưng nó chỉ cung cấp rất ít ...

+0

Thảo luận gần như trùng lặp ở đây: http://stackoverflow.com/questions/396513/should-parameters-returns-of-collections-be-ienumerablet-or-t –

Trả lời

2

Nếu bạn muốn tất cả các dịch vụ của bạn trả về cùng một giao diện thì có thể tôi sẽ truy cập IEnumerable<>.

Nó sẽ được dễ dàng đủ cho người gọi của bạn để chuyển đổi sang IQueryable hoặc tạo một List, nếu cần thiết:

IEnumerable<Car> cars = Searcher.CarsStartingWith("L"); 
var carsList = cars.ToList(); 
var queryableCars = cars.AsQueryable(); 
+0

Hoàn toàn đồng ý. Bạn nên luôn sử dụng hợp đồng tối thiểu cần thiết. IEnumerable có thể được tiêu thụ hoặc chuyển đổi bởi nhiều loại BCL, như bạn đã chứng minh. –

+0

Đúng. Tôi quyết định trả lại IEnumerable. Và nếu một IList có ý nghĩa hơn trong một trường hợp cụ thể, tôi sẽ sử dụng quy ước đặt tên để làm cho những phương pháp đó nổi bật so với đám đông. –

+4

Vấn đề với việc trả về 'IEnumerable 'là nếu bạn quyết định bạn muốn chuyển đổi nó thành' IQuerable ', bạn không còn truy vấn đối với DB, nhưng đối với các đối tượng trong bộ nhớ. Như James Curran đã chỉ ra rằng 'IQueryable' hơi đắt tiền, nhưng trong hầu hết các kịch bản của tôi, tôi thấy rằng việc cung cấp một tập hợp có thể truy vấn được tốt hơn là để người tiêu dùng quyết định xem họ có muốn đưa nó xuống IEnumerable hay không. –

3

tôi sẽ chọn IEnumerable bởi vì nó có một vị trí trung tâm hơn trong khuôn khổ, cung cấp tính linh hoạt cho những người cần đến nó, trong khi cũng cung cấp quen thuộc cho những người chưa bị mắc kẹt vào những thứ như LINQ.

+0

Tôi thích IEnumerable, nếu chỉ có một cách để cung cấp cho nó là một phương pháp đếm. Tôi biết nó là cố hữu để được lười biếng để không biết có bao nhiêu có, nhưng tài sản Count chỉ là một cái gì đó bạn cần rất nhiều lần! –

+0

LINQ cung cấp phương thức mở rộng Đếm cho IEnumerable. –

+0

@ Jeff không phải là một ý tưởng tốt nếu bản gốc là một IQueryable (nó sẽ được lấy ra và tính). – eglasius

2

IQueryable sẽ có một yêu cầu khá nặng về nó - bạn không thể, ví dụ, trả về một mảng.

Thông thường đối với tôi, sự lựa chọn giữa IEnumerable hoặc IList thường kết thúc là tùy theo điều kiện nào dễ thực hiện hơn trong trường hợp chuẩn.

+0

Tương tự cho tôi cho đến nay. Nhưng tôi đang cố gắng trở nên nhất quán hơn một chút trong phong cách lập trình của mình. Và tôi nghĩ tôi sẽ ném IQueryable vào bởi vì các giao diện chất lỏng thường trông rất dễ đọc. –

2

Câu trả lời ngắn: Phụ thuộc.

Câu trả lời dài hơn: Trả về loại giàu nhất mà mã khách hàng của bạn sẽ cần. IList hoạt động trong hầu hết các trường hợp nếu bạn không cần tải chậm. Bạn vẫn có thể sử dụng LINQ để truy vấn đối với một IList hoặc IEnumerable. Nếu tải chậm là một yêu cầu, sau đó đi với IEnumerable hoặc IQueryable.

Lưu ý phụ: Quay trở lại cùng một giao diện cho tất cả các dịch vụ có vẻ giống như một mục tiêu cao quý nhưng được cung cấp các mẫu sử dụng khác nhau, bạn có thể muốn trả về các giao diện khác nhau.

+0

Đúng, có thể là quy ước đặt tên tùy thuộc vào việc anh lười biếng/không lười biếng có thể thú vị. –

+0

Tôi muốn tranh cãi theo cách khác. IList cung cấp cách nhiều hơn IEnumerable và vì vậy bạn nên chọn IEnumerable, bất kể đánh giá lười biếng, trừ khi bạn cần thêm các phương thức như Add, Remove, và indexing. –

2

Luôn đi với IEnumerable trừ khi bạn có một lý do nghiêm trọng không. Sau đó, bạn có thể triển khai trình nâng cấp với yield return.

IQueryable là một loại cá hoàn toàn khác biệt. Không phải cái gì bạn tình cờ thực hiện như là một thay thế cho một container điển hình trong bộ nhớ.

Trong số còn lại, có sự khác biệt lớn giữa IEnumerable và các mục khác: chỉ đọc.

+0

Truyền giá trị trả về cho IEnumerable không làm cho nó chỉ đọc: nó có thể được truyền lại bằng cách gọi. Nếu bạn muốn chỉ đọc, hãy bọc kết quả trong bộ sưu tập chỉ đọc (ví dụ: sử dụng Danh sách (T) .AsReadOnly) trước khi trả lại. Tôi thường trả về IList (T) hoặc ICollection (T) khi người gọi thường muốn đếm. – Joe

+1

Tất nhiên - tôi có nghĩa là nó được gõ tĩnh để có thể đọc được. Bạn cũng có thể nói "Không có trường tạo điểm riêng tư - chúng có thể sử dụng sự phản chiếu để có được chúng". –

3

Quy tắc của ngón tay cái là như sau:

Nếu có bao giờ là một cơ hội mà tôi có thể đưa thuật toán cốt lõi của thói quen và cấu trúc lại nó trong một cách mà tôi có thể sử dụng lợi nhuận năng suất, tôi sẽ đi với IEnumerable <T>.Ví dụ: nếu triển khai hiện tại của tôi sử dụng mảng hoặc danh sách <T> nội bộ, nhưng tôi biết rằng, ít nhất về mặt lý thuyết, tôi có thể muốn và có khả năng làm lại nội bộ để đánh giá lười biếng, tôi sẽ trả lại một số IE2umeric <T>.

Tôi đã nhận thấy rằng lợi ích của việc trả lại số điện thoại <T> chắc chắn đáng để sử dụng nó.

Tuy nhiên, nếu thuật toán, trong bản chất của nó, sẽ cần phải đánh giá đầy đủ kết quả trước khi trở về (hiếm, nhưng không xảy ra), tôi sẽ đi với một số <T>. Về cơ bản, nếu tôi đã tính toán nó, tôi sẽ trả lại nó. IList <T> thực hiện IEnumerable <T>, vì vậy tất cả các trường hợp sử dụng LINQ liên quan vẫn hoạt động, nhưng bạn bị mất đánh giá lười biếng. Nếu tôi đã buộc phải đánh giá trước, đó không phải là một vấn đề.

Tôi hiếm khi trả về IQueryable. Thời gian duy nhất tôi sẽ sử dụng giao diện này là nếu tôi trực tiếp tạo ra một lớp truy cập dữ liệu có thể truy vấn, hoặc một cái gì đó tương tự. Chi phí của việc sử dụng này là, trong hầu hết các trường hợp, không đáng giá.

Tuy nhiên, nếu mục tiêu của bạn là luôn sử dụng một giao diện duy nhất (tôi không nhất thiết phải đồng ý với mục tiêu này), tôi sẽ dính vào IEnumerable <T>.

0

Nếu bạn đang sử dụng IQueryable làm kiểu trả về, Bạn có một lớp dịch vụ có trừu tượng bị rò rỉ.

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