2012-04-16 40 views
5

可能重複:
Collection<T> versus List<T> what should you use on your interfaces?確定返回內部列表<T>作爲IEnumerable <T>或ICollection <T>?

考慮這個方法,返回的變量myVarList<T>,但該方法MyMethod()的返回類型是IEnumerable<T>

public IEnumerable<T> MyMethod(string stuff) 
{ 
    var myVar = new List<T>(); 
    //do stuff 

    return myVar; 
} 

本質上,我想知道的是如果returni ng myVar作爲不同的類型是可以的。

具體而言,就我的情況而言,'do stuff'會經過DataRow並將該DataRow中的項目分配給對象列表。在其他地方,我也有類似的情況與ICollectionIList返回類型。

我想退回IEnumerableICollection的原因是,我沒有回覆超過需要。但是同時,如果需要的話,這允許調用者將返回值轉換爲List

但是,我的返回語句返回List而不是方法的返回類型是奇怪的。這是正常的做法嗎?這樣做有什麼問題嗎?

澄清(響應欺騙評論):

只是爲了澄清,我很好奇的是,如果它是好的,在我的身體return語句返回一個List<T>,但該方法標題有返回類型IEnumerable,或可能有ICollection,Collection等等......有些東西不同比比例返回聲明。

+2

調用者不應該從IEnumerable轉換爲List。它返回接口的原因是因爲如果存在底層列表,可超集,簡單數組或甚至是通過yield return返回的列表,應該沒有關係。 – aqwert 2012-04-16 22:29:48

+1

這兩個建議的模式更接近於彼此的模式,而不是這個問題給他們,我想,儘管它們都是密切相關的。 – 2012-04-16 22:54:37

+0

@ChrisCharabaruk我同意這個問題不是重複的,我已經重寫了它,希望更好地傳達我認爲獨特的東西。我也投票重新提出了這個問題。 – DavidRR 2015-12-03 15:57:41

回答

6

不僅沒有錯,它實際上是一個好習慣:只暴露嚴格必需的東西。這樣,調用者不能依賴於該方法將返回List<T>的事實,所以如果由於某種原因需要更改實現以返回其他內容,則不會違反合同。但是,如果(錯誤地)對該方法實際返回的假設做出了假設,則調用代碼可能會中斷

+0

「....並且調用者可以將它轉換爲List,如果它需要的話」這聽起來已經是意圖了,仍然是一個好習慣? – 2012-04-16 22:34:32

+0

@TimSchmelter,好吧,如果調用者被認爲*知道該方法返回一個List,那麼返回類型應該是List,當然......這不是一個好習慣的問題,只是一個常識問題;) – 2012-04-16 22:38:42

+0

然後驗證,我的返回語句返回一個列表,但該方法的返回類型是IEnumerable ,這沒關係? – RJP 2012-04-16 23:49:28

2

它沒有問題。

實際返回具體類是滿足「返回接口」要求的唯一方法。

如果您讓特定類的知識潛入調用代碼(List<T> r = (List<T>)MyMethod("ff")),可能會有缺點。但是如果你把結果當作接口(如你所想的那樣)就沒關係。

3

返回IEnumerable<T>類型的原因是,它們調用者無法修改列表(而不是將其重新轉換爲列表)。如果您注意到所有(大多數?)擴展方法採用IEnumerable<T>參數,以便您知道該擴展方法不會修改您的列表。其次,List<T>繼承IEnumerable<T>

編輯: 正如托馬斯在評論該IEnumerable<T>可以被調用者轉換回一List<T>和修改的解釋。如果您的主要目標是使其成爲只讀,您可以返回列表myVar.AsReadOnly()。但是那種類型是ReadOnlyCollection<T>

+0

不確定是否阻止修改是主要原因 – zerkms 2012-04-16 22:31:47

+1

它不會阻止調用者修改列表:調用代碼仍然可以將結果投遞到列表。但是,這樣做意味着對實現做出無法證明的假設,所以如果實現發生變化,它可能會中斷。 – 2012-04-16 22:33:40

+0

並返回'ReadOnlyCollection '保留返回值的數組語義。也就是說,一個項目可以通過其整數索引來檢索。並且可以在不需要迭代集合的情況下獲得集合中的項目數量。 – DavidRR 2015-12-03 16:07:15

1

我認爲這不是最優的,因爲它允許調用者投射到List<T>,這依賴於實現細節。我會添加一些掩碼,例如Select(x=>x)

一個動態類型的調用者可能甚至不會注意到您將您的列表投射到IEnumerable<T>。對他來說簡直就是List<T>

返回一個內部永久List<T>IEnumerable<T>將是非常錯誤的,因爲它允許調用者改變你的類的內部狀態。但是,由於您在每次調用中都返回一個新的List<T>實例,因此在其他地方沒有使用該實例,因此該示例中不適用此參數。

+0

如果你想這樣做,你也可以使用迭代器;) – 2012-04-16 22:39:19

+0

用東西包裝列表會增加無用的運行時包袱。但是,也許有人可能會返回一個'List '99次100次,並且只偶爾返回一個包裝?這會破壞轉換爲List的代碼,但不會太糟糕。 – supercat 2012-04-16 22:50:56

+0

@supercat因爲對於99%的代碼,這個小的開銷並不重要,如果我的分析表明它很重要,我只會擔心它。 – CodesInChaos 2012-04-16 22:54:10

相關問題