为什么“while”在C#中如此受欢迎?

时间:2009-04-18 10:08:57

标签: c# for-loop iteration while-loop

问题字段有点太短,无法提出我真正的问题。如果有人能够更好地概括一下,请随意。

我真正的问题是:我现在正在阅读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);

7 个答案:

答案 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>