一、定義 IEnumerable ICollection IList List 可以看到功能上List最強大,性能上IEnumerable更好,其實性能上都差不多,都是介面。 二、IEnumerable<T>和IQueryable<T> 的區別 IEnumerable<T> 是linq to obj ...
一、定義
IEnumerable
public interface IEnumerable<out T> : IEnumerable
ICollection
public interface ICollection<T> : IEnumerable<T>, IEnumerable
IList
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
List
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
可以看到功能上List最強大,性能上IEnumerable更好,其實性能上都差不多,都是介面。
二、IEnumerable<T>和IQueryable<T> 的區別
IEnumerable<T> 是linq to object。
IQueryable<T> 是linq to sql。
打個比方,我從Users中獲取1條數據 var q=db.Users.orderby(x=>x.id).Take(1);
對於IEnumerable<T>來說,他先會把所有數據載入到記憶體,然後在取一條數據。
對於IQueryable<T> 來說,他會生成一個sql語句,只是取一條數據
三、介面設計中,函數的返回值應該怎麼選擇?
留意 .net 的類庫,會發現很少有方法返回 List<T> 或 IList<T> 的,但是很多 .net 的程式員喜歡這麼做,為什麼?因為 List<T> 的功能實在太強大了吧。
IEnumerable<T> 是延時求值的,如果在調用棧裡面輸入和輸出都是 IEnumerable<T> 的話,是最好的,因為無論調用多少次,迴圈都只有一次,.NET 裡面的 lambda 就是這樣的。
但是調用棧的輸入輸出無法確定的時候,情況就比較複雜。如果你返回的是 IEnumerable<T>,有可能調用棧的上一層執行了它的迭代器,造成並不需要的多次迴圈。
如果調用棧的上一層使用的是 List<T> 的 Copy() 方法,那麼你返回 List<T> 會比較好,如果你返回的是 IEnumerable<T>,一般是會被 ToList() 再 Copy()
所以這個問題關鍵還是看怎麼使用返回值,來決定你編寫的函數的返回值。
使用儘可能底層的、具體的類型。不要從一開始就超過你的需求來搞“抽象”。因此首先是使用 List<T>。
能返回List就不要返回IList:如果後面有方法需要IList可以直接傳;如果後面需要用到List的屬性就能直接用
如果返回的是IList:後面有方法需要List,你得想想我能不能轉,或者回去改;如果需要用到List的屬性,還得回去改,綜上考慮返回範圍更廣的類型好處多多。
但是,隨著你真正開始需要抽象了,你就“被迫”需要重構為抽象的類型了。這時候再重構,要在必須的時候才進行抽象。真正會抽象的人,肯定是反而不濫用抽象,是在必須的時候才抽象的。這個道理大概是“從不抽象設計”的人總也不能理解的。
有的人,很實際,你看到他的代碼就知道他的這部分程式設計已經到達那個程度、必須抽象才能用在系統中。其返回的具體數據類型“確實是”多種子類型定義的,所以才抽象。這就是把複雜的介面弄得剛剛合適的聲明程度。
而有的人,代碼的抽象總是高於實際,中間存在著含糊的、不確定的因素,明明其輸入輸出的數據類型不具有抽象、多態處理,卻要弄一個很抽象的定義。這就是把簡單的事情弄複雜了。
假設說你設計的時候,你有多種實際子類型的考慮,你確實有多種實現代碼,那麼你就返回一個枚舉類型,明確地告訴使用者“我不能返回集合類型,我不保證實現所有的集合類型才有的功能”。這是因為你現在要實現的東西,確實是不能用集合類型的。
反過來說,如果你輸出的東西只能用集合類型,那麼就返回集合類型,方便調用者傻瓜化地使用。將來還有其它複雜的擴展,那麼應該重構介面,增加重載新方法,而不用去修改原來使用集合類型的東西。比如說 Linq 有一系列的基於枚舉類型的功能方法,但是不是說原來基於集合類型而定義的一大堆方法就不應該設計出來。不需要放這個馬後炮。所以根據現在實際情況,定義介面,習慣於經常在新版本中重構介面,而不是糾結在“一次性‘最完美’不再變”的介面,就可以了。
比如多層項目中,數據層,業務層,展現層三層中,從數據層查詢數據集到展現層需要“傳遞”2次,如果是List或者IEnumerable,會在數據層就將數據載入到記憶體,另外對於一個方法返回List集合,接受數據時每次都new 一個List集合 我感覺是不妥的,如果數據量較大是很損性能。 而IQueryable對於數據的操作,會根據自定義的擴展方法 來生成最終的查詢語句,而不是從一開始就載入數據,這就達到了哪裡需要數據就在哪裡查詢。其實很多項目中都會有直接返回LIst的方法或者介面,這些方式難免是那些從培訓中心從來的或者從一些書籍上看到的開發人員編寫的。
抽象都是恰到好處地抽象,才叫抽象!