23

在以下示例中:

  • 一个似乎更冗长但不那么浪费资源
  • 第二不那么冗长但更浪费资源(重新定义每个循环的字符串)

哪个是更好的编码实践?

第一个例子:

using System;
using System.Collections.Generic;

namespace TestForeach23434
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> names = new List<string> { "one", "two", "two", "three", "four", "four" };

            string test1 = "";
            string test2 = "";
            string test3 = "";
            foreach (var name in names)
            {
                test1 = name + "1";
                test2 = name + "2";
                test3 = name + "3";
                Console.WriteLine("{0}, {1}, {2}", test1, test2, test3);
            }
            Console.ReadLine();
        }
    }
}

第二个例子:

using System;
using System.Collections.Generic;

namespace TestForeach23434
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> names = new List<string> { "one", "two", "two", "three", "four", "four" };

            foreach (var name in names)
            {
                string test1 = name + "1";
                string test2 = name + "2";
                string test3 = name + "3";
                Console.WriteLine("{0}, {1}, {2}", test1, test2, test3);
            }
            Console.ReadLine();
        }
    }
}
4

12 回答 12

46

第二种形式不再浪费 - 它只是更好。

在循环之外声明变量没有任何好处,除非你想在迭代之间保持它们的值。

(请注意,这通常不会产生行为差异,但如果变量是由 lambda 表达式或匿名方法捕获的,则情况并非如此。)

于 2010-03-05T17:28:13.793 回答
18

就我个人而言,考虑到它们的用法,我认为在尽可能严格的范围内声明变量是最佳实践。

这提供了许多好处:

  1. 重构更容易,因为当变量已经在同一范围内时,提取方法更简单。
  2. 变量用法更清晰,这将导致更可靠的代码。

唯一的(潜在的)缺点是额外的变量声明——然而,JIT 倾向于优化这个问题,所以在实际工作中我不一定会担心。

一个例外:

如果您的变量将增加大量 GC 压力,并且如果可以通过 foreach/for 循环重用相同的对象实例来避免这种情况,并且如果 GC 压力导致测量的性能问题,我会将其提升到外部范围。

于 2010-03-05T17:29:49.503 回答
5

这些既浪费又冗长。

foreach (var name in names)
{
   Console.WriteLine("{0}1, {0}2, {0}3", name);
}

.

</tongueincheek>
于 2010-03-05T17:27:46.963 回答
2

根据语言和编译器的不同,它可能相同也可能不同。对于 C#,我希望生成的代码非常相似。

我自己的哲学很简单:

优化以便于理解。

其他任何事情都是过早的优化!大多数开发中最大的瓶颈是开发人员的时间和注意力。如果您绝对必须挤出最后一个 CPU 周期,那么一定要这样做,但除非您有令人信服的业务需要或正在编写关键组件(公共库、操作系统内核等),否则最好等到您可以对完成的程序进行基准测试。那时优化一些最昂贵的例程是合理的,在此之前几乎可以肯定是浪费时间。

于 2010-03-05T17:32:19.787 回答
1

我不确定通过在循环之外定义字符串变量可以获得什么。字符串是不可变的,因此它们不会被重用。每当您分配给它们时,都会创建一个新实例。

于 2010-03-05T17:29:08.323 回答
0

我发现在循环之外“提升”声明通常是一种更好的长期维护策略。编译器通常会对性能进行可接受的排序。

于 2010-03-05T17:30:23.573 回答
0

我认为这取决于您要解决的问题。我喜欢第二个示例,因为您可以一步移动代码。我喜欢第一个示例,因为堆栈操作更少、内存碎片更少以及对象构造/创建更少,它更快。

于 2010-03-05T17:29:22.397 回答
0

就性能而言,它们几乎相同(字符串是不可变的),但就可读性而言……我想说两者都不是很好。您可以轻松地在 Console.WriteLine 中完成所有操作。

也许您可以发布真正的问题而不是示例?

于 2010-03-05T17:36:25.740 回答
0

我通常将变量声明为尽可能接近它们的用途,在这种情况下,这将是您的第二个示例。Resharper 也倾向于鼓励这种风格。

于 2010-03-05T18:22:46.053 回答
0

对于 POD 类型数据,声明最接近首次使用。对于诸如执行任何内存分配的类之类的任何事情,您应该考虑在任何循环之外声明它们。字符串几乎肯定会进行某种形式的分配,并且大多数实现(至少在 C++ 中)将尽可能尝试重用内存。基于堆的分配确实可能非常慢。

我曾经分析过一些 C++ 代码,其中包含一个在其 ctor 中包含新数据的类。使用在循环外声明的变量,它的运行速度比在循环内声明的变量快 17%。C# 中的 YMMV 如此分析性能,您可能会对结果感到非常惊讶。

于 2010-03-05T19:38:38.357 回答
0

这是我最喜欢的 Linq 部分,我想它适合这里:

names.ForEach(x => Console.WriteLine("{0}1, {0}2, {0}3", x));
于 2016-10-21T11:27:21.297 回答
-1

声明变量时遵循一个简单的规则

在第一次需要时声明它

于 2010-03-05T17:31:35.817 回答