我一直認爲返回數組比使用公共API時的列表要好,但現在似乎在列表中可以通過LINQ等獲得所有這些函數。什麼是在API中返回的最佳集合類型
爲了返回原始對象或對象的集合,這裏改變了最佳實踐嗎?
例如:
Order[] GetOrders();
List<Order> GetOrders();
IEnumerable<Order> GetOrders();
IQueryable<Order> Get Orders();
我一直認爲返回數組比使用公共API時的列表要好,但現在似乎在列表中可以通過LINQ等獲得所有這些函數。什麼是在API中返回的最佳集合類型
爲了返回原始對象或對象的集合,這裏改變了最佳實踐嗎?
例如:
Order[] GetOrders();
List<Order> GetOrders();
IEnumerable<Order> GetOrders();
IQueryable<Order> Get Orders();
我覺得最常用的類型是IEnumerable<T>
yield
關鍵字IEnumerable<T>
返回類型,這使得你的方法延遲枚舉和執行。 (例如,常見的投訴是System.IO.Path.GetFiles()不返回IEnumerable<T>
,但返回一個Array,這意味着當您調用該方法時,無論您是否需要,都需要枚舉所有項目。您有List<T>
相同的缺點)IEnumerable<T>
IEnumerable<T>
返回類型工作,不承擔具體的有關呼叫者的東西。如果調用者需要一個列表或數組,他們總是可以創建一個。IEnumerable<T>
由List<T>
和Array
執行,因此很容易改變您的方法的實現,並仍然支持以前的返回類型。只要確保你不允許某人將你的'IEnumerable
你想要集合是不可改變的嗎? IEnumerable<T>
可變嗎? IList<T>
你需要索引嗎? IList<T>
與列表或陣列,該API消費者有充分的能力來添加,刪除,刪除,清除等
隨着IEnumerable<T>
,該API消費者獲得一個項目的「包」,沒有特別順序,沒有索引,也沒有方法修改集合。
在一些有限的情況下,您可能想要返回IQueryable<T>
,但它們通常專用於逐個構建查詢。
一般而言,我會默認爲IEnumerable<T>
。我可能會使用List<T>
作爲後臺字段,但只希望允許用戶以Add()
爲例 - 不要刪除,清除或其他任何內容,因此我聲明public void Add<T>(T item)
只是將該項添加到後臺字段列表中。
如果您不需要索引,請不要忘記ICollection
除了其他人所說的內容之外,我想補充說,除非您從某個遠程數據源檢索對象,否則不應該返回IQueryable。 IQueryable是一個查詢對象,它將代表調用者獲取結果。當使用LINQ時,IQuearyable通常會使用表達式樹來轉換以供其他系統(例如Sql Server)使用。
請參閱http://weblogs.asp.net/fredriknormen/archive/2008/12/01/returning-iqueryable-lt-t-gt.aspx瞭解更多詳情。
正如我通常只從屬性/方法返回不可變(不可修改)的對象,這個答案假設你想要做同樣的事情。
不要忘了ReadOnlyCollection<T>
它返回一個仍然可以通過索引訪問的不可變集合。
如果您使用IEnumerable<T>
和釋放你的類型到無法控制的曠野,警惕的是:
class MyClass {
private List<int> _list;
public IEnumerable<int> Numbers {
get { return _list; }
}
}
由於用戶可以做到這一點,並弄亂你的類的內部狀態:
var list = (List<int>)myClass.Numbers;
list.Add(123);
這會違反財產的只讀意圖。在這種情況下,您的吸氣器應如下所示:
public IEnumerable<int> Numbers {
get { return new ReadOnlyCollection<int>(_list); }
}
或者,您可以撥打_list.ToReadOnly()
。我全部寫出來顯示類型。這將阻止任何修改你的狀態的人(除非他們使用反射,但除非你構建像許多函數式編程語言中使用的那樣的不可變集合,這真的很難停止,而這是一個完整的其他故事)。
如果您要返回只讀集合,則最好將成員聲明爲ReadOnlyCollection<T>
,因爲某些操作執行得更快(獲取計數,按索引訪問項目,複製到另一個集合)。
個人而言,我希望看到的框架包括和使用的界面是這樣的:
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);
}
你可以使用上的IEnumerable<T>
頂部擴展方法所有這些功能,但它們沒有高性能的。
請注意,以上所有類型都支持不同程度的Linq,可以通過'IEnumerable'或'IQueryable '。 –
2010-06-28 03:49:41