2010-06-28 16 views
9

Tôi luôn nghĩ rằng việc trả lại Mảng tốt hơn danh sách khi có API công khai nhưng có vẻ như tất cả các chức năng này đều có trong danh sách có sẵn thông qua LINQ, v.v.loại bộ sưu tập tốt nhất để trở lại trong API

Thực hành tốt nhất có thay đổi ở đây để trả lại các bộ sưu tập nguyên thủy hoặc các đối tượng không?

ví dụ:

Order[] GetOrders(); 
List<Order> GetOrders(); 
IEnumerable<Order> GetOrders(); 
IQueryable<Order> Get Orders(); 
+0

Lưu ý rằng tất cả các loại trên hỗ trợ LINQ với các mức độ khác nhau, hoặc thông qua 'IEnumerable 'hoặc' IQueryable '. –

Trả lời

5

Tôi nghĩ rằng các loại thông dụng nhất là IEnumerable<T>

  • Với một loại IEnumerable<T> bù lại bạn có thể sử dụng từ khóa yield và điều này cho phép trì hoãn liệt kê và thực hiện các phương pháp của bạn . (Một khiếu nại phổ biến cho ví dụ là System.IO.Path.GetFiles() không trả lại một IEnumerable<T> nhưng trả về một mảng có nghĩa là khi bạn gọi phương thức tất cả các mục cần được liệt kê bất kể bạn có cần hay không. bạn có những bất lợi cùng với List<T>)
  • Hầu hết các phương pháp khuyến nông LINQ làm việc trên một IEnumerable<T>
  • các IEnumerable<T> kiểu trả về không thừa nhận bất cứ điều gì cụ thể về người gọi. Nếu người gọi cần danh sách hoặc mảng, họ có thể luôn tạo danh sách hoặc mảng.
  • IEnumerable<T> được triển khai bởi List<T>Array và do đó dễ thay đổi việc triển khai phương pháp của bạn và vẫn hỗ trợ loại trả về trước đó.
+0

Chỉ cần đảm bảo rằng bạn không cho phép ai đó bỏ 'IEnumerable ' của bạn vào, ví dụ, một 'Danh sách ' và thay đổi nó nếu điều đó sẽ phá vỡ một bất biến của lớp. Xem câu trả lời của tôi để biết thêm chi tiết. –

5

Bạn có muốn bộ sưu tập không thay đổi được không? IEnumerable<T> Có thể thay đổi? IList<T>

Bạn có cần chỉ mục không? IList<T>

Với một danh sách hoặc mảng, người tiêu dùng API có đủ năng lực để thêm, xóa, xóa, rõ ràng vv

Với một IEnumerable<T>, người tiêu dùng API được một "túi" các mặt hàng, không có đặc biệt thứ tự, không có chỉ mục và không có phương pháp nào để sửa đổi bộ sưu tập.

Có một số trường hợp giới hạn mà bạn có thể muốn trả về IQueryable<T>, nhưng chúng thường dành riêng cho việc xây dựng các truy vấn từng phần.

Nói chung, tôi muốn mặc định là IEnumerable<T>. Tôi có thể sử dụng List<T> làm trường sao lưu, nhưng chỉ muốn cho phép người dùng Add(), ví dụ - không xóa, xóa hoặc bất kỳ thứ gì khác, vì vậy tôi khai báo một số public void Add<T>(T item) chỉ thêm mục vào danh sách trường sao lưu.

+0

Đừng quên ICollection nếu bạn không cần chỉ mục. IList thực hiện ICollection và chỉ thêm một chỉ mục, IndexOf (mục T), Chèn (chỉ mục int, mục T) và RemoveAt (chỉ mục int). –

1

Ngoài những gì người khác đã nói tôi muốn thêm rằng bạn không bao giờ nên trả lại IQueryable trừ khi bạn đang truy xuất các đối tượng từ một số nguồn dữ liệu từ xa. IQueryable là đối tượng truy vấn sẽ tìm nạp kết quả thay mặt cho người gọi. Khi sử dụng LINQ, một IQuearyable thường sẽ lấy một cây biểu thức sẽ được dịch để sử dụng bởi một số hệ thống khác (ví dụ: Sql Server).

Xem http://weblogs.asp.net/fredriknormen/archive/2008/12/01/returning-iqueryable-lt-t-gt.aspx để biết thêm chi tiết.

5

Vì tôi thường chỉ trả về các đối tượng bất biến (không thể sửa đổi) từ thuộc tính/phương thức, câu trả lời này giả định bạn muốn làm như vậy.

Đừng quên về ReadOnlyCollection<T> trả về bộ sưu tập không thể thay đổi mà vẫn có thể được truy cập theo chỉ mục.

Nếu bạn đang sử dụng IEnumerable<T> và phát hành loại của bạn vào vùng hoang dã không kiểm soát được, hãy cảnh giác về điều này:

class MyClass { 
    private List<int> _list; 
    public IEnumerable<int> Numbers { 
     get { return _list; } 
    } 
} 

Là một người dùng có thể thực hiện điều này và mess lên trạng thái nội bộ của lớp học của bạn:

var list = (List<int>)myClass.Numbers; 
list.Add(123); 

Điều này sẽ vi phạm ý định chỉ đọc cho thuộc tính. Trong những trường hợp như vậy, người khởi xướng của bạn sẽ trông giống như sau:

public IEnumerable<int> Numbers { 
     get { return new ReadOnlyCollection<int>(_list); } 
    } 

Hoặc bạn có thể gọi _list.ToReadOnly(). Tôi đã viết nó ra đầy đủ để hiển thị loại. Điều này sẽ ngăn chặn bất kỳ ai thay đổi trạng thái của bạn (trừ khi họ sử dụng sự phản chiếu, nhưng điều đó thực sự khó ngăn trừ khi bạn xây dựng những bộ sưu tập bất biến như những sử dụng trong nhiều ngôn ngữ lập trình hàm, và đó là một câu chuyện khác).

Nếu bạn chỉ trả lại các bộ sưu tập chỉ đọc, bạn nên khai báo thành viên là ReadOnlyCollection<T> khi một số hành động nhất định thực hiện nhanh hơn (đếm, truy cập các mục theo chỉ mục, sao chép sang bộ sưu tập khác).

Cá nhân tôi muốn xem khuôn khổ bao gồm và sử dụng một giao diện như thế này:

public interface IReadOnlyCollection<T> : IEnumerable<T> 
{ 
    T this[int index] { get; } 
    int Count { get; } 
    bool Contains(T item); 
    void CopyTo(T[] array, int arrayIndex); 
    int IndexOf(T item); 
} 

Bạn có thể nhận được tất cả các chức năng này sử dụng phương pháp khuyến nông trên đầu trang của IEnumerable<T> nhưng chúng không phải là performant.

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