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

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

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

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

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

using System; using System.Collections.Generic; namespace TestForeach23434 { class Program { static void Main(string[] args) { List names = new List { "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 names = new List { "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(); } } } 

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

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

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

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

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

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

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

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

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

Они являются расточительными и многословными.

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

,

  

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

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

Оптимизируйте для удобства понимания.

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

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

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

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

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

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

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

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

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

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

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

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

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