簡體   English   中英

創建封裝Generic Collection的類有缺點嗎?

[英]Are there drawbacks to creating a class that encapsulates Generic Collection?

我的(C#3.0 .NET 3.5)應用程序的一部分需要維護幾個字符串列表。 我毫不奇怪地將它們聲明為List<string>並且一切正常,這很好。

這些List的字符串實際上(並且始終)是基金ID。 我想知道更明確的意圖是否更具意圖,例如:

public class FundIdList : List<string> { }

......這也有效。 從技術上還是哲學上來說,這有什么明顯的缺點嗎?

我將從另一個方向開始:將字符串包裝到名為FundId的類/結構中。 我認為,這樣做的優勢大於通用列表與專用列表。

  1. 您的代碼變得類型安全:將表示其他內容的字符串傳遞給需要基金標識符的方法的范圍要小得多。
  2. 您可以將構造函數中有效的字符串約束為FundId,即強制執行最大長度,檢查代碼是否為預期格式,&c。
  3. 您可以添加與該類型相關的方法/功能。 例如,如果以“I”開頭的基金代碼是內部基金,您可以添加一個名為IsInternal的屬性來形式化。

至於FundIdList,擁有這樣一個類的優勢類似於FundId上面的第3點:你有一個地方可以掛鈎在FundIds列表上運行的方法/函數(即聚合函數)。 如果沒有這樣的地方,你會發現靜態幫助器方法開始在整個代碼中出現,或者在一些靜態助手類中出現。

List <>沒有虛擬或受保護的成員 - 這些類幾乎不應該是子類。 此外,雖然你可能需要List<string>的全部功能,但如果你這樣做 - 是否有必要制作這樣的子類?

子類化有各種缺點。 如果您將本地類型聲明為FundIdList ,那么您將無法通過例如使用linq和.ToList來分配它,因為您的類型更具體。 我看到人們決定在這些列表中需要額外的功能,然后將其添加到子類列表類中。 這是有問題的,因為List實現忽略了這些額外的位並且可能違反了你的約束 - 例如,如果你要求唯一性並聲明一個新的Add方法,那么任何人(例如)通過將列表作為一個簡單地(合法地)向上轉換為List<string>任何人這樣輸入的參數將使用默認列表Add,而不是新的Add。 您只能添加功能,永遠不會刪除它 - 並且沒有需要子類化來利用的受保護或虛擬成員。

因此,您無法使用擴展方法添加任何功能,並且您的類型不再完全兼容,這限制了您可以對列表執行的操作。

我更喜歡聲明一個包含字符串的struct FundId ,並實現有關該字符串所需的任何保證,然后使用List<FundId>而不是List<string>

最后,你真的是指List<>嗎? 我看到很多人使用List<>來處理IEnumerable<>或plain數組更適合的事情。 在api中公開內部List特別棘手,因為這意味着任何API用戶都可以添加/刪除/更改項目。 即使您首先復制列表,這樣的返回值仍然會產生誤導,因為人們可能希望能夠添加/刪除/更改項目。 如果您沒有在API中公開List ,而只是將其用於內部簿記,那么聲明和使用不添加任何功能的類型(僅文檔)並不是那么有趣。

結論

僅對內部使用List<> ,如果這樣做,則不要將其子類化。 如果你想要一些顯式的類型安全,請在結構中包裝string (不是類,因為結構在這里更有效並且具有更好的語義:在null的FundId和空字符串之間沒有混淆,並且對象相等和哈希碼工作為預期結構但需要手動指定類)。 最后,如果您需要支持枚舉,或者如果您還需要索引,則使用簡單的ReadOnlyCollection<>包裝器來展示IEnumerable<> ,而不是讓API客戶端使用內部位。 如果您確實需要可變列表API, ObservableCollection<>至少可以讓您對客戶端所做的更改做出反應。

我個人會把它FundId List<string> ,或者可能創建一個包裝字符串然后存儲List<FundId>FundId類。

List<FundId>選項將強制執行類型更正,並允許您對FundIds進行一些驗證。

只需將其保留為List<string> ,您的變量名稱就足以告訴其他人它正在存儲FundID。

var fundIDList = new List<string>();

我什么時候需要繼承List<T>

如果您對基金ID列表有特殊的操作/操作,請繼承它。

public class FundIdList : List<string> 
{
   public void SpecialAction()
   {
      //can only do with a fund id list
      //sorry I can't give an example :(
   }
}

除非我想要某人做他們可以做的所有事情來List<string> ,而沒有對FundIdList進行任何干預,我寧願實現IList<string> (或者如果我不關心的話,可以實現層次結構更高層次的接口大多數接口的成員)並在適當時委托調用私有List<string>

如果我確實希望有人擁有這種程度的控制權,我可能只是首先給他們一個List<string> 據推測,你有一些東西可以確保這些字符串實際上是“基金ID”,當你公開使用繼承時,你不能再保證。

實際上,這聽起來(並且經常使用List<T> )就像私有繼承的自然情況一樣。 唉,C#沒有私有繼承,所以組合是要走的路。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM