14

我最近问某人为什么他更喜欢返回强类型数组而不是 IList。我一直认为,面对一个生命周期很长的项目时,针对接口编程是最灵活、最好的编程方式。所以当他回答时,我感到很奇怪:

我们通常更喜欢不可变类型而不是可变类型。数组是不可变的。IList 不是。

我不完全确定我理解这个说法。任何人都可以帮助澄清这一点吗?

感谢你们提供的任何帮助。

4

11 回答 11

13

无论“他”是谁,在这个话题上都是 100% 错误的。数组是一个非常可变的。这实际上是不返回数组的原因之一。没有办法阻止调用者将数组的元素更改为他们喜欢的任何内容。

数组不可变的唯一方法是它的长度。一旦分配了一个数组,它的长度就不能改变。即使是 Array.Resize 等 API 实际上也不会调整数组的大小,它们只是分配一个新数组,复制内容并返回新数组(在本例中通过引用)。

但是,我确实同意在许多情况下最好返回不可变数据。第一个是它允许您返回对类的内部集合的引用,而无需进行完整的复制,同时防止调用者弄乱您的内部状态。大多数可变集合不能做出这样的保证。

于 2009-05-02T23:47:02.233 回答
11

我想他可能认为因为数组的长度属性是不可变的,那么数组在某种程度上比 IList不可变,或者他使用了错误的词并将具体与不可变互换。谁知道,但这是一个奇怪的答案。

我认为返回 List 有一些暗示可以修改它,或者在返回数组时它可能会改变并不意味着那么多。

例如,如果您在存储库顶部有一个对象模型,并且有一个像 GetCars() 这样返回 List 的方法,而初级程序员看到了 cars.Add(Car c) ... 你会认为他的想法完全是疯狂的吗? cars.Add(new Car()) 可能实际上将汽车添加到存储库中?数组本质上更明确。

我认为 List 的使用在属性中更合适,比如 Page.Controls.Add

出于几个原因,我更喜欢返回数组而不是 List。

  • 习惯。1.0/1.1 中的集合 SUCKED

  • 我更喜欢我的方法返回尽可能简单和最轻量级的对象。如果我需要将 Array 设为 List,这很简单。

  • 它们可以在 .net 1.1 中使用,如果我需要支持旧版本的运行时,它可以减少重构的表面,我可以至少重用我的一些代码或应用相同的对象模型。

于 2009-05-03T11:33:19.803 回答
10

我总是更喜欢ReadOnlyCollection。列表的所有优点,但只读。

于 2009-05-03T11:39:09.727 回答
7

他可能的意思是 IList 包含 Insert、Remove 和 Add 方法,因此可以修改集合本身。另一方面,T[] 不能添加元素。

我应该补充一点,FxCop 建议改为返回 ReadOnlyCollection。索引器是只读的,因此不能更改元素,并且 Add 和其他此类方法都抛出 NotSupportedException。

于 2009-05-02T23:44:37.217 回答
7

原则上他是对的,但他不知道如何正确练习......

我们通常更喜欢不可变类型而不是可变类型。

那是对的。不可变类型更易于使用

数组是不可变的。IList 不是。

这是不正确的。这些都不是一成不变的。

如果要返回不可变的集合,请返回 anIEnumerable<T>或 a ReadOnlyCollection<T>(使用List<T>.AsReadOnly方法)。如果它们本身不是不可变的,它们仍然不能保护对象。尽管您只能从集合中读取数据,但如果它们允许,您仍然可以更改每个对象中的数据。

此外,您应该考虑您要返回的集合的“所有权”。如果您创建数组的唯一目的是返回它,那么没有理由不完全控制它。另一方面,如果您要返回一个作为该类成员的集合,则您应该只允许尽可能少地访问它。

于 2009-05-03T00:21:05.210 回答
2

我也不明白。数组是非常可变的,除了它们的大小。仍然可以修改单个元素。也许他的意思是数组是值类型而列表是引用类型。我不知道。

无论如何,您可能应该看看Eric Lippert对这个主题的看法。也可以为您提供一些弹药供讨论。

于 2009-05-02T23:38:51.643 回答
1

也许这个人不知道他在说什么?

于 2009-05-02T23:36:26.360 回答
1

使用接口作为返回类型而不是实际类型本身的原因是对调用者隐藏内部实现。这允许实现更改实际类型,而不会重复应用程序的其余部分。

将内部使用的集合复制到数组中以供外部使用是没有任何意义的,除了可变或不可变之外没有其他原因。

单独的问题是: - 是否返回强类型数据列表。IList 或 IList。始终首选使用强类型数据。- 可变或不可变。ICollection、IList 或 IEnumerator 返回您希望允许的数据。对于只读列表,仅返回一个 IEnumerator。如果允许调用者修改集合,请使用 ICollection 或 IList。

于 2009-05-03T02:45:42.677 回答
0

基本上他的意思是“我们更喜欢在运行时不容易更改的结构,因为我们相信它们不太容易出错。” 在这种情况下这是否正确是另一个问题。

于 2009-05-02T23:36:35.143 回答
0

也许他的意思是数组的大小是“不可变的”?基本上,您声明一次大小,然后就被卡住了。对于列表,您始终可以使用“添加”。

如果确定列表的大小,也许数组会快一点?

于 2009-05-02T23:45:17.120 回答
0

好。IList 是可变的,因为您可以添加和删除项目,而不仅仅是更改已经存在的项目。数组可以让您处理单个项目,但特定索引永远不会变得完全无效。有很多理由更喜欢不变性——例如,它使意外数据损坏的表面积小得多。

于 2009-05-02T23:46:08.723 回答