【发布时间】:2010-07-24 03:45:21
【问题描述】:
for 关键字在 C# 或 Java 等语言中是否已过时或可能会像 goto 一样过时?再过几年,看到一个使用for的面向对象代码会不会很奇怪,像今天一样,看到gotos就很可疑?
换句话说,有什么理由知道并在程序中使用for?
我注意到for 有很多在使用foreach 时不存在的弱点:
'For' 很少使用,我们也很少需要它:
不了解科学发展,但是做一般的东西,软件产品和网站,特别是不涉及微积分,for 很少使用。我见过并做过很多项目,在数千行代码中没有 for 循环。可能即使在处理微积分时,操作 arrays、collections 或 matrices 或 ranges 也更频繁、更优雅并且比循环有用。
有几个地方看似需要for,其实不然,可以改用面向集合的方案。
阅读初学者开发者的源代码,我还发现for 曾经做过.NET Framework 已经做过的事情。例如,用相同的值填充一个数组,重复N次,有些人会使用循环,而他们必须使用Enumerable.Repeat()。
有时,我看到循环用于遍历数组、集合或枚举。 foreach 将是一个更优雅的解决方案,并且写起来更短。
'For' 不是Jimmy-proof:
可能我是一个非常糟糕的开发人员,但很多时候,当我使用for 时,我会一次又一次地犯同样的错误:在循环范围内放置预定义变量以外的内容,如下所示:
int SomeValue
{
get
{
// Resources-expensive operation goes here.
}
}
for (int i = 0; i < this.SomeValue; i++)
{
// Code here.
}
// Instead, a less stupid developer would write:
int someValue = this.SomeValue;
for (int i = 0; i < someValue; i++)
{
// ...
}
当然,这样做的问题是每次迭代都会调用this.SomeValue,浪费资源。例如,今天晚上,我发现自己犯了一个可怕的错误:循环使用了 0..N 范围,其中 N 是对数据库进行查询的属性.在 SQL Profiler 中看到 相同的查询 被重复了 10 000 次真是令人惊讶。
'For' 很丑:
也许这太主观了,但是当一直在操作集合时,第二个解决方案不是更自然地写/读吗?
// Solution 1. C style.
for (int i = 0; i < 10; i++)
{
// Do something.
}
// Solution 2. Enumerable-oriented.
foreach (var i in Enumerable.Range(0, 10))
{
// Do something.
}
顺便说一句,我发现第二个更容易理解。区别是:
for (i = 0; i < 10; i++)
for (i = 0; i <= 10; i++)
for (i = 1; i < 10; i++)
for (i = 1; i <= 10; i++)
容易看到吗?而Enumerable.Range() 只接受两个参数,非常明确:第一个 - 从哪里开始,以及元素的数量。
更复杂的代码呢?
foreach (string containingTwo in Enumerable.Range(0, 10).
Where(c => c.ToString().Contains('2')).
Select(c => c.ToString().PadLeft(8)))
{
Console.Write(containingTwo);
}
'For' 太死板了:
很难扩展for。假设我们想在不使用 ASP.NET 分页控件的情况下显示网站上的页面列表。最明显的解决方案是使用for (int i = 1; i <= countPages; i++) 显示数字。
现在,如果需求发生变化,我们不想显示每个页面,而只显示前两个、最后两个、当前页面和与当前最近的页面,该怎么办?
如果我们使用一个集合,它会很容易改变。实际上,使用循环,它不是。
'For' 对 Linq 不友好:
Linq 可以做很多事情,避免手写。但是当我们使用for 时,Linq 就没有地方了。如果有过滤要做,我们必须自己做。如果必须转换结果,则必须在单独的行上完成。是的,当然,lambda 表达式也可以在一个简单的循环中使用,但是没有一种易于阅读的方法可以在一行短代码中编写所有内容。 Sum 或 Average 不可用,就像 Join 或 Except 或 GroupBy 一样。
【问题讨论】:
-
你把它命名为所有通用 OO 语言然后只谈论 .NET,当然你不明白为什么还要使用
for -
我会说
goto并没有过时,这会让人们感到不安。这是一个很少有用的工具,没错,但有时它是迄今为止最好的解决方案。这是关于可读性和可维护性 - 而不是性能。当您的逻辑流程最好使用状态图来描述时,每个转换的最简单和最清晰的表示就是 goto。问题是这个参数只有在你的代码不需要保存它的状态然后再恢复时才有效,在这种情况下循环切换习惯用法更有意义——但即使这样,一个单独的线程也可以轻松地挂起自己。 -
另外,在您的
i = someValue上 - (1) 我假设您的意思是i == someValue,并且 (2) 优化器通常可以为您将其从循环中拉出来,尽管不可否认它经常会赢t(例如,如果 operator== 不是内联的,则无法知道是否存在预期的副作用)。 -
@Steve314:这是一个错误:
i = someValue必须是i < someValue。在我的情况下(当数据库被查询数千次时),内联是不可能的:编译器无法预测数据库在循环内没有改变。 -
这是强烈的观点,我建议将其设为社区 wiki。
标签: c# for-loop readability