问题字段有点太短,无法提出我真正的问题。如果有人能够更好地概括一下,请随意。
我真正的问题是:我现在正在阅读C#中的很多其他人的代码,我注意到一种特定的迭代形式被广泛传播(参见代码)。 我的第一个问题是:
所有这些迭代都是等价的吗?
我的第二个是:为什么更喜欢第一个?它与可读性有关吗?现在我不相信第一种形式比for-form更容易阅读,而且可用性在这些结构中是一个主观项目,当然,你最常用的形式似乎更具可读性,但我可以向所有人保证,for-form至少具有可读性,因为它只有一行,你甚至可以阅读构造中的初始化。
因此第二个问题:为什么第三种形式在代码中看得少得多?
// the 'widespread' construct
int nr = getNumber();
while (NotZero(nr))
{
Console.Write(1/nr);
nr = getNumber();
}
// the somewhat shorter form
int nr;
while (NotZero(nr = getNumber()))
Console.Write(1 / nr);
// the for - form
for (int nr = getNumber(); NotZero(nr); nr = getNumber())
Console.Write(1 / nr);
答案 0 :(得分:5)
所有这些迭代都是等价的吗?
是
为什么选择第一个?有吧......与可读性有关?
因为您可能希望将nr var的范围扩展到while循环之外?
为什么第3种形式在代码中看得少得多?
它是等同的,同样的陈述! 您可能更喜欢后者,因为您不想扩展nr变量的范围
答案 1 :(得分:5)
您显示的第一个和第三个表单重复调用GetNumber。我更喜欢第二种形式,虽然它具有在一定条件下使用副作用的缺点。但是我几乎只用做一个while循环。通常我最终不会将结果作为参数传递 - 我发现自己的常见情况是:
string line;
while ( (line = reader.ReadLine()) != null)
...
和
int bytesRead;
while ( (bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
...
这些对我来说都是如此惯用,以至于它们不会给我带来任何问题 - 正如我所说,它们只允许我说出一次逻辑。
如果您不喜欢具有太多范围的变量,您可以引入一个额外的块:
{
int bytesRead;
while ( (bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
// Body
}
}
就我个人而言,我不倾向于这样做 - “太宽”的范围并不会让我感到非常困扰。
我怀疑编写一个方法来封装所有这些并不太难。类似的东西:
ForEach(() => reader.ReadLine(), // Way to obtain a value
line => line != null, // Condition
line =>
{
// body
};
请注意,对于读行,我有一个有帮助的课程:
foreach (string line in new LineReader(file))
{
// body
}
(它不仅适用于文件 - 它非常灵活。)
答案 2 :(得分:3)
我认为第三种形式(for-loop)是这些替代方案中最好的,因为它将事物放在正确的范围内。另一方面,不得不重复调用getNumber()也有点尴尬。
一般来说,我认为显式循环被广泛滥用。高级语言应该提供映射,过滤和减少。当这些高级构造适用且可用时,循环就像使用goto
而不是循环。
如果映射,过滤或缩小不适用,我可能会为这种循环编写一个小宏(C#没有那些,但是,是吗?)。
答案 3 :(得分:3)
我提供另一种选择
foreach (var x in InitInfinite(() => GetNumber()).TakeWhile(NotZero))
{
Console.WriteLine(1.0/x);
}
其中InitInfinite是一个简单的辅助函数。整个计划:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static IEnumerable<T> InitInfinite<T>(Func<T> f)
{
while (true)
{
yield return f();
}
}
static int N = 5;
static int GetNumber()
{
N--;
return N;
}
static bool NotZero(int n) { return n != 0; }
static void Main(string[] args)
{
foreach (var x in InitInfinite(() => GetNumber()).TakeWhile(NotZero))
{
Console.WriteLine(1.0/x);
}
}
}
答案 4 :(得分:2)
我认为人们经常使用while()循环,因为它最能代表您在头脑中可视化任务的方式。我认为使用它比任何其他循环结构都有任何性能优势。
答案 5 :(得分:2)
这是随机推测:
当我编写C#代码时,我编写的唯一两个循环结构是while()和foreach()。也就是说,没有人再使用'for',因为'foreach'经常起作用并且通常更优越。 (这是一个过度概括,但它有一个真实的核心。)因此,我的大脑必须紧张阅读任何'for'循环因为它不熟悉。
答案 6 :(得分:1)
至于为什么(1)和(2)比(3)更“优先”,我的感觉是大多数人认为后者是一种迭代范围的方法,使用条件来定义范围,而不是在某些情况仍然存在的情况下,继续迭代一个块。关键字语义适合这种解释,我怀疑,部分原因是,人们发现表达式在该上下文中最具可读性。例如,我绝不会使用(1)或(2)迭代范围,尽管我可以。
在(1)和(2)之间,我被撕裂了。我以前经常使用(2)(在C中)由于紧凑性,但现在(在C#中)我通常写(1)。我想我已经开始重视可读性而不是紧凑性了(1)似乎更容易快速解析,因此即使我最终重复了少量逻辑,我也会更加可读。
老实说,我很少写while语句,通常使用foreach - 或LINQ - 在以前使用while语句的情况下。想想看,我不确定我是否会使用很多语句,除了在单元测试中我生成一些固定数量的测试对象。</ p>