在Code Review.stackexchange询问我的问题之后,我被建议使用以下代码片段。我注意到在传输过程中string [] 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();
}
答案 0 :(得分:13)
到目前为止,所有的答案都表明,在你接受的内容中更为通用会使你的帮助方法更有用。这是对的。但是,还有其他一些考虑因素。
Pro:采用序列而不是数组与正在调用代码的开发人员进行通信“我不会改变你传递给我的对象”。当我调用一个接受数组的方法时,我怎么知道它不会改变数组呢?
Con:采用更通用的类型意味着您的方法必须对于更通用类型的任何实例都是正确的。你怎么知道这是对的?测试。因此,采用更通用的类型可能意味着更大的测试负担。如果您采用数组,那么您只有几种情况:空数组,空数组,协变数组等。如果您采用序列,则要测试的案例数量会更大。
你提到了表现。请记住,根据感受而不是经验数据做出微观决策是获得良好表现的可怕方法。相反,设定一个绩效目标,根据该目标衡量进度,并使用分析器找到最慢的东西;首先攻击。数组上的foreach
循环编译为等效的for
循环;在IEnumerable
上代码更复杂,可能慢几微秒。您的应用程序在市场中的成功或失败是由这些微秒决定的吗?如果是这样,那么小心测量性能。如果没有,请按照您喜欢的方式编写代码,如果您引入了导致您不再符合目标的回归,则自动化测试会告诉您相关信息。您正在运行自动化性能测试,对吧?如果你非常关心表现,你应该是。
答案 1 :(得分:12)
数组是 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
几乎可以是任何事情。
答案 2 :(得分:4)
查看Law of Demeter。您希望参数尽可能通用,以便在更多情况下使用它们。
现在您传入任何实现IEnumerable
的集合,并且不仅限于数组。
在这种情况下,它更多的是设计问题,而不是性能问题。返回值是一个不同的情况,因为那里肯定会有一些性能提升。
在这种情况下,你只是在迭代,所以IEnumerable
就是你所需要的一切
答案 3 :(得分:2)
IEnumerable仅提供最小的可迭代的&#34;功能。你可以遍历序列,但这是关于它的。这有缺点 - 例如,使用IEnumerable计算元素或获取第n个元素是非常低效的 - 但它也有优势 - 例如,IEnumerable可能是无穷无尽的序列,如素数序列。
Array是一个固定大小的集合,具有随机访问权限(即您可以将其编入索引)
答案 4 :(得分:1)
在上面的代码中它没有任何区别,因为你有物化数组,IEnumerable如果你使用
会真的有帮助System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
while((line = file.ReadLine()) != null)
{
yield return line;
}
file.Close();
这里 因此,在上面的代码中,我们将始终只在内存中有一行,有助于读取更大的文件大小而只消耗少量字节的内存。
另外一般规律是将输入参数传递给函数类型应该是广泛接受的,因为IEnumerable是由所有集合和基于集合的接口实现的,所以将参数类型设置为IEnumerable是个好主意,这样你就可以传递List或者任何其他收藏类型。