繁体   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