与数组相比,使用IEnumerable的优势是什么
本文关键字:是什么 IEnumerable 使用 数组 | 更新日期: 2023-09-27 18:25:30
在CodeReview.stackeexchange上询问我的问题后,建议我使用以下代码段。我注意到,在传输过程中,字符串[]Lines被设置为IEnumerable。
在查看了IEnumerable函数一段时间后,我没有发现任何性能改进的迹象。那么这只是为了可读性吗?或者使用IEnumerable而不是数组是否确实存在性能差异或总体优势?
private void ProcessSingleItem(String fileName, String oldId, String newId)
{
string[] lines = File.ReadAllLines(fileName);
File.WriteAllText(fileName, ProcessLines(lines, oldId, newId));
}
private String ProcessLines(IEnumerable<String> lines, String oldId, String newId)
{
StringBuilder sb = new StringBuilder(2048);
foreach (String line in lines)
{
sb.AppendLine(line.Replace(oldId, newId));
}
return sb.ToString();
}
到目前为止,所有的答案都表明,对所接受的内容更加通用会使您的helper方法更加有用。这是正确的。然而,还有其他考虑因素。
-
Pro:使用序列而不是数组可以与调用您代码的开发人员进行通信:"我不会改变您传递给我的对象"。当我调用一个接受数组的方法时,我怎么知道它不会更改数组?
-
Con:采用更通用的类型意味着您的方法对于该更通用类型的任何实例都必须是正确的。你怎么知道它是正确的?测试。因此,采用更通用的类型可能意味着更大的测试负担。如果你取一个数组,那么你只有几种情况:空数组、空数组、协变数组等等。
-
你提到了表演。记住,基于感觉而不是经验数据做出微观决策是获得良好业绩的糟糕方法。相反,设定一个性能目标,根据该目标衡量你的进度,并使用探查器来找到最慢的东西;先攻击它。数组上的
foreach
循环编译为等效的for
循环;在CCD_ 3上,代码更复杂并且可能慢几微秒。你的应用程序在市场上的成败将由这些微秒决定吗?如果是,则小心测量性能。如果没有,按照你喜欢的方式编写代码,如果你引入了一个回归,导致你不再达到目标,你的自动化测试会告诉你这一点。你正在运行自动化性能测试,对吧?如果你如此关心表现,你应该如此。
数组是IEnumerable
的实现。
方法中lines
参数中使用的唯一成员是在IEnumerable
中定义的成员。因此,您可以选择IEnumerable
作为参数类型,并且在接受什么方面最不挑剔,从而允许将任何IEnumerable
实现作为参数提供。
考虑这个例子:
ProcessLines(GetItems(), ...);
public IEnumerable<string> GetItems()
{
yield return "ItemAlwaysGetsIncluded";
if (!once_in_blue_moon)
{
yield break;
}
yield return "ItemIncludedOnceInABlueMoon";
}
很难说性能的影响是什么,因为IEnumerable
几乎可以是任何东西。
看看德米特定律。您希望参数尽可能通用,以便在更多情况下使用。
现在,您可以传入任何实现IEnumerable
的集合,这些集合不仅限于数组。
在这种情况下,与其说是性能问题,不如说是设计问题。返回值是另一种情况,因为肯定会有一些性能提升。
在这种情况下,您只是在迭代,所以IEnumerable
就是您所需要的
IEnumerable只提供最小的"可迭代"功能。你可以遍历序列,但仅此而已。这有缺点——例如,使用IEnumerable计数元素或获取第n个元素的效率非常低——但它也有优点——例如,IEnumeraable可以是一个无尽的序列,就像素数序列一样。
数组是一个具有随机访问功能的固定大小集合(即,您可以对其进行索引)
在上面的代码中,它没有任何区别,因为您已经物化了数组,如果您使用,IEnumerable将非常有用
System.IO.StreamReader file = new System.IO.StreamReader("c:''test.txt");
while((line = file.ReadLine()) != null)
{
yield return line;
}
file.Close();
这里因此,在上面的代码中,我们将始终在内存中只有一行,这有助于读取更大大小的文件,而只消耗几个字节的内存。
此外,一般规律是,将输入参数传递给函数类型应该是广泛可接受的,因此,由于所有集合和基于集合的接口都实现了IEnumerable,因此最好将参数类型设置为IEnumeraable,这样您就可以传递List或任何其他集合类型。