Лучше ли программировать, чтобы определять переменные вне foreach, хотя и более многословно? - PullRequest
23 голосов
/ 05 марта 2010

В следующих примерах:

  • первый кажется более многословным, но менее затратным из ресурсов
  • секунда менее многословна, но более расточительна (переопределяет строку в каждом цикле)

Какая практика кодирования лучше?

Первый пример:

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();
        }
    }
}

Ответы [ 12 ]

45 голосов
/ 05 марта 2010

Вторая форма не более расточительна - она ​​просто лучше.

Нет смысла объявлять переменные вне цикла, если вы не хотите сохранять их значения между итерациями.

(Обратите внимание, что обычно это не имеет никакого поведенческого различия, но это не так, если переменные захватываются лямбда-выражением или анонимным методом.)

18 голосов
/ 05 марта 2010

Лично я считаю, что лучше всего объявлять переменные в максимально возможной области, учитывая их использование.

Это дает много преимуществ:

  1. Рефакторинг проще, так как извлечение метода проще, когда переменные уже находятся в той же области видимости.
  2. Использование переменной более понятно, что приведет к более надежному коду.

Единственным (потенциальным) недостатком было бы дополнительное объявление переменных - однако JIT имеет тенденцию оптимизировать эту проблему, поэтому я не буду беспокоиться о ней в реальной работе.

Единственное исключение:

Если ваша переменная будет добавлять большое давление ГХ, и , если этого можно избежать путем повторного использования одного и того же экземпляра объекта в цикле foreach / for, и , если давление ГХ вызывает измеренные проблемы с производительностью, я бы поднял его наружу.

5 голосов
/ 05 марта 2010

Это и расточительно, и многословно.

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

.

</tongueincheek>
2 голосов
/ 05 марта 2010

В зависимости от языка и компилятора оно может быть или не быть одинаковым.Для C # я ожидаю, что полученный код будет очень похожим.

Моя собственная философия в этом проста:

Оптимизация для простоты понимания.

Все остальное - преждевременная оптимизация!Самое большое узкое место в большинстве разработок - это время и внимание разработчика.Если вам абсолютно необходимо выжать каждый последний цикл ЦП, то непременно сделайте это, но если у вас нет острой необходимости в бизнесе или вы пишете критически важный компонент (общая библиотека, ядро ​​операционной системы и т. Д.), Вам лучше подождать, пока выможно сравнить готовую программуВ то время оптимизация некоторых из самых дорогостоящих процедур оправдана, а раньше это почти наверняка пустая трата времени.

1 голос
/ 05 марта 2010

Я не уверен, что вы получите, определив строковую переменную вне цикла. Строки являются неизменяемыми, поэтому они не используются повторно. Всякий раз, когда вы назначаете им, создается новый экземпляр.

0 голосов
/ 21 октября 2016

Это моя любимая часть Linq, которая, я думаю, подходит здесь:

names.ForEach(x => Console.WriteLine("{0}1, {0}2, {0}3", x));
0 голосов
/ 05 марта 2010

Для данных типа POD объявляйте наиболее близкие к первому использованию. Для чего-либо подобного классу, который выполняет какое-либо распределение памяти, вам следует рассмотреть возможность объявления тех, которые находятся вне каких-либо циклов. Строки почти наверняка будут выполнять некоторую форму выделения, и большинство реализаций (по крайней мере, в C ++) будут пытаться повторно использовать память, если это возможно. Распределение на основе кучи может быть очень медленным.

Однажды я профилировал немного кода C ++, который включал класс, который new'd данные в своем ctor. С переменной, объявленной вне цикла, она работала на 17% быстрее, чем с переменной, объявленной внутри цикла. YMMV в C #, так что производительность профиля вы можете быть очень удивлены результатами.

0 голосов
/ 05 марта 2010

Я обычно объявляю переменные настолько близкими к их использованию, насколько позволяет область видимости, что в этом случае будет вашим вторым примером.Решарпер также поддерживает этот стиль.

0 голосов
/ 05 марта 2010

Они оба практически одинаковы с точки зрения производительности (строки неизменяемы), но что касается читабельности ... Я бы сказал, что ни один из них не очень хорош. Вы можете легко сделать все это в Console.WriteLine.

Возможно, вы можете опубликовать реальную проблему вместо примера?

0 голосов
/ 05 марта 2010

Следуйте простому правилу при объявлении переменных

Объявите, когда вам это понадобится впервые

...