c# string[] vs IEnumerable<string>

17

如果我在运行之前就知道元素数量,应该选择什么?

Resharper 给了我 IEnumerable<string> 而不是 string[]


你需要重新思考你的问题。目前你的问题并不清晰,我们无法理解你的疑问。显然,string[]和IEnumerable<string>是两个不同的概念。 - Stephen Chung
始终使用列表而不是数组 - 这是我的规则。 - Pabuc
3
在某些情况下,应该优先选择数组,特别是在性能和内存使用至关重要的情况下。 - Jakub Konecki
1
@Stephen的问题很清楚,如果你熟悉那个ReSharper标志的话。 - Yuriy Faktorovich
这是一个很棒的问题,如果人们理解了,只有两个投票? :o - nawfal
9个回答

7
ReSharper建议使用IEnumerable<string>如果您仅使用IEnumerable定义的方法。这样做是因为,由于您显然不需要将值作为数组进行类型化,您可能希望将确切类型隐藏在(即使用)该值的代码的消费者(即消费者)之前,因为您可能希望在将来更改类型。
在大多数情况下,采用建议是正确的选择。差异不是您可以在程序运行时观察到的内容;而是在未来更改程序时,您会发现它的易用性。
从上面可以推断出,除非我们正在跨越方法边界传递值(我不记得R#是否也提供了局部变量的建议/问题),否则整个建议/问题都没有意义。

4
如果ReSharper建议您使用IEnumerable<string>,那么这意味着您只使用了该接口的功能,而没有使用任何数组特定的功能。按照ReSharper的建议进行更改。

3
实际类型应该是string[],但根据用户的需求,您可能希望将其公开为其他类型。例如:IEnumerable<string> sequence = new string[5]... 特别是如果它是像static readonly这样的内容,那么您应该将其设置为ReadOnlyCollection,以便条目不可修改。

3

如果您试图将此方法作为其他方法的接口提供,则我更喜欢使您的方法输出更加通用,因此会选择 IEnumerable<string>

在方法内部,如果您正在尝试实例化并且不会传递到其他方法,则我会选择 string[]。尽管我不需要 延迟执行,但在这种情况下使用哪种都无所谓。


在一个方法内部,传递 string[]IEnumerable<string> 对延迟执行没有影响。 - Mark Sowul
@Domenic:没错,我们可以将许多东西转换为IEnumerable并执行相同的操作。但是,这里的重点只是在两者之间独立选择。 - Mahesh Velaga
1
@Downvoter:请说明下投反对票的原因,以便改进回答。谢谢。 - Mahesh Velaga
@Mahesh:这里没有进行任何转换;事实上,string[]List<string>或许多其他类型都_实现了_IEnumerable<string>。对于这样的类型,您总是会得到延迟执行,因此您声称声明不同类型对延迟执行有任何影响是错误的。 - Domenic
@Domenic,有趣的是人们如何读心。没有单独提到任何声明,只是讨论类型,而且——发帖者正在声明某些内容。你用数组举的例子没有意义,因为你使用了自动声明,所以“ordered”将成为IEnumerable。如果你想从中获取数组,你需要实例化集合,比如ToArray,这会导致执行。你简单地混淆了被调用者和结果类型。 - greenoldman
显示剩余7条评论

3

使用 string[],你可以通过索引访问项目;而使用 IEnumerable,你需要循环查找特定索引。


3
它可能是因为在你的代码中寻找更好的Liskov替换,所以这样建议你。请记住声明类型和实现类型之间的区别。IEnumerable<>不是一种实现,而是一种接口。你可以将变量声明为IEnumerable<string>并用string[]构建它,因为字符串数组实现了IEnumerable<string>
这样做的好处是,允许你将该字符串数组作为一种更通用、更抽象的类型传递。任何期望或返回IEnumerable<string>的内容(无论实现方式是List<string>string[]还是其他任何东西)都可以使用你的字符串数组,而不必担心你传递的具体实现。只要满足接口,它就是正确类型的多态。
记住这并非总是正确的选择。有时候,作为开发者,你对实现非常关心(例如可能进行非常细致的性能调优),不想使用抽象层。这个决定由你做出。ReSharper只是建议在变量/方法声明中使用抽象层而不是实现。

1

ReSharper 可能会为您标记它,因为您没有返回最不受限制的类型。如果您将来不打算使用索引访问它,我建议使用 IEnumerable,以减少返回它的方法的约束。


1

这取决于您以后的使用。如果您需要枚举这些元素,或者以后需要对它们进行排序或比较,则建议使用IEnumerable,否则使用数组。


1

我为一个类似的关于数组或IEnumerable用于返回值的问题撰写了这个回答,但在我发布之前它就被关闭了。我认为这个答案可能对一些人有趣,所以在这里发布。

IEnumerable相对于T[]的主要优点是,IEnumerable(用于返回值)可以变成惰性。也就是说,在需要下一个元素时才计算它。

考虑一下Directory.GetFiles和Directory.EnumerateFiles之间的区别。GetFiles返回一个数组,而EnumerateFiles返回IEnumerable。这意味着对于一个有两百万个文件的目录,数组将包含两百万个字符串。而EnumerateFiles只在需要时实例化字符串,节省了内存并提高了响应时间。

然而,并不是所有都是好处。

foreach在非数组上显着不够有效(通过反汇编ILCode可以看到这一点)。

Array承诺更多,即其长度不会改变。

惰性求值并不总是更好,考虑Directory类。GetFiles实现将打开一个查找文件句柄,迭代所有文件,关闭查找文件句柄,然后返回结果。EnumerateFiles将什么也不做,直到请求第一个查找文件,然后打开查找文件句柄并迭代文件,在枚举器被处理时关闭查找文件句柄。这意味着查找文件句柄的生命周期由调用者控制,而不是被调用者控制。可以看作是封装性较差,并且可能会在锁定文件句柄时产生潜在的运行时错误。

在我看来,我认为R#过于热衷于建议使用IEnumerable而不是数组,特别是对于返回值(输入参数具有较少的潜在缺点)。当我看到返回IEnumerable的函数时,我倾向于使用.ToArray以避免潜在的惰性求值问题,但如果集合已经是数组,则这种方法效率低下。

我喜欢这个原则:承诺很多,要求很少。即不要求输入参数必须是数组(使用IEnumerable),但是返回Array而不是IEnumerable,因为Array是一个更大的承诺。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接