Лучше ли практика кодирования определять переменные за пределами foreach, хотя они более подробные?

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

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

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

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

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

Ответы

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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

.

</tongueincheek>

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

Я думаю, это зависит от того, что вы пытаетесь решить. Мне нравится второй пример, потому что вы можете переместить код за один шаг. Мне нравится первый пример, потому что он быстрее из-за меньшего количества манипуляций со стеком, меньшей фрагментации памяти и создания/создания объектов меньше.

Ответ 7

Я обнаружил, что декларации "подъема" из циклов обычно являются лучшей долгосрочной стратегией обслуживания. Компилятор обычно будет разбирать вещи приемлемо для производительности.

Ответ 8

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

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

Ответ 9

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

Ответ 10

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

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

Ответ 11

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

names.ForEach(x => Console.WriteLine("{0}1, {0}2, {0}3", x));

Ответ 12

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

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