У меня есть небольшой фрагмент кода, который анализирует значение индекса для определения ввода ячейки в Excel. Это заставило меня задуматься ...
какая разница между
xlsSheet.Write("C" + rowIndex.ToString(), null, title);
и
xlsSheet.Write(string.Format("C{0}", rowIndex), null, title);
Один «лучше» другого? И почему?
Ответы:
До C # 6
Честно говоря, я думаю, что первая версия проще - хотя я бы упростил ее до:
Я подозреваю, что в других ответах может говориться о снижении производительности, но, честно говоря, оно будет минимальным, если оно вообще будет присутствовать - и эта версия конкатенации не требует синтаксического анализа строки формата.
Строки формата отлично подходят для целей локализации и т. Д., Но в таком случае объединение проще и работает так же хорошо.
С C # 6
Строковая интерполяция упрощает чтение в C # 6. В этом случае ваш второй код выглядит следующим образом:
что, вероятно, лучший вариант, ИМО.
источник
xlsSheet.Write($"C{rowIndex}", null, title);
Мое первоначальное предпочтение (исходя из опыта работы с C ++) было для String.Format. Позже я отказался от этого по следующим причинам:
- Конкатенация строк допускает нулевые значения,String.Format
но не допускает . Запись «s1 + null + s2
» не нарушает работу, она просто обрабатывает нулевое значение как String.Empty. Что ж, это может зависеть от вашего конкретного сценария - бывают случаи, когда вам нужна ошибка вместо того, чтобы молча игнорировать пустое имя FirstName. Однако даже в этой ситуации я лично предпочитаю сам проверять нули и выдавать определенные ошибки вместо стандартного исключения ArgumentNullException, которое я получаю из String.Format.Идея в том, что компилятор .NET достаточно умен, чтобы преобразовать этот фрагмент кода:
к этому:
Что происходит под капотом String.Concat, легко догадаться (используйте Reflector). Объекты в массиве преобразуются в свою строку с помощью ToString (). Затем вычисляется общая длина и выделяется только одна строка (с общей длиной). Наконец, каждая строка копируется в результирующую строку через wstrcpy в небезопасном фрагменте кода.
Причины
String.Concat
быстрее? Что ж, мы все можем посмотреть, чтоString.Format
происходит - вы будете удивлены объемом кода, необходимого для обработки строки формата. Вдобавок ко всему (я видел комментарии относительно потребления памяти)String.Format
внутренне использует StringBuilder. Вот как:StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
Таким образом, для каждого переданного аргумента резервируется 8 символов. Если аргумент представляет собой однозначное значение, то очень плохо, у нас есть потраченное впустую место. Если аргумент - это настраиваемый объект, возвращающий некоторый длинный текст
ToString()
, тогда может потребоваться некоторое перераспределение (конечно, в худшем случае).По сравнению с этим конкатенация только тратит впустую пространство массива объектов (не слишком много, учитывая массив ссылок). Нет никакого синтаксического анализа для спецификаторов формата и никакого промежуточного StringBuilder. Накладные расходы на упаковку / распаковку присутствуют в обоих методах.
Единственная причина, по которой я выбрал String.Format, - это локализация. Размещение строк формата в ресурсах позволяет поддерживать разные языки, не вмешиваясь в код (подумайте о сценариях, в которых форматированные значения меняют порядок в зависимости от языка, например, "через {0} часов и {1} минут" на японском языке может выглядеть совершенно иначе: ).
Подводя итог моему первому (и довольно длинному) посту:
ToString()
вызововToString()
сами, чтобы избежать бокса (я несколько склонен к удобочитаемости) - так же, как первый вариант в вашем вопросеString.Format()
имеет преимущество.источник
string.Format
«безопасно» при использовании ReSharper; то есть он так же безопасен, как и любой другой код, который можно использовать [неправильно]. 2)string.Format
это допускает «сейф»null
:string.Format("A{0}B", (string)null)
результаты в «AB». 3) Меня редко волнует такой уровень производительности (и поэтому я редко когда выхожу из игрыStringBuilder
) ...string s = "This " + MyMethod(arg) + " is a test";
компилируется дляString.Concat()
вызова в режиме Release.Я думаю, что первый вариант более читабелен, и это должно быть вашей главной заботой.
string.Format использует StringBuilder под капотом (проверьте с помощью отражателя ), поэтому он не будет иметь никакого преимущества в производительности, если вы не выполните значительную конкатенацию. Это будет медленнее для вашего сценария, но на самом деле это решение по оптимизации микропроизводительности неуместно большую часть времени, и вам действительно следует сосредоточиться на удобочитаемости вашего кода, если вы не зацикливаетесь.
В любом случае, сначала напишите для удобства чтения, а затем используйте профилировщик производительности для определения ваших горячих точек, если вы действительно думаете, что у вас есть проблемы с производительностью.
источник
Для простого случая, когда это простая одиночная конкатенация, я чувствую, что это не стоит сложностей
string.Format
(и я не тестировал, но подозреваю, что для такого простого случая, как этот,string.Format
может быть немного медленнее, что с синтаксическим анализом строки формата и все). Как и Джон Скит, я предпочитаю не вызывать явно.ToString()
, поскольку это будет сделано неявноstring.Concat(string, object)
перегрузкой, и я думаю, что код выглядит более чистым и его легче читать без него.Но я определенно предпочитаю больше, чем несколько конкатенаций (сколько это субъективно)
string.Format
. В какой-то момент я думаю, что и удобочитаемость, и производительность излишне страдают от конкатенации.Если в строке формата много параметров (опять же, «многие» субъективно), я обычно предпочитаю включать в аргументы замены закомментированные индексы, чтобы не упустить из виду, какое значение соответствует какому параметру. Надуманный пример:
Обновить
Мне приходит в голову, что приведенный мной пример немного сбивает с толку, потому что, похоже, я использовал как конкатенацию, так и
string.Format
здесь. И да, логически и лексически это то, что я сделал. Но все конкатенации будут оптимизированы компилятором 1 , поскольку они все строковые литералы. Таким образом, во время выполнения будет одна строка. Итак, я думаю, я должен сказать, что предпочитаю избегать множества конкатенаций во время выполнения .Конечно, большая часть этой темы уже устарела, если вы все еще не застряли на C # 5 или старше. Теперь у нас есть интерполированные строки , которые по удобочитаемости намного превосходят их
string.Format
почти во всех случаях. В наши дни, если я просто не конкатенирую значение непосредственно в начало или конец строкового литерала, я почти всегда использую интерполяцию строк. Сегодня я бы написал свой предыдущий пример так:Таким образом, вы теряете конкатенацию во время компиляции. Каждая интерполированная строка превращается в вызов
string.Format
компилятора, и их результаты объединяются во время выполнения. Это означает, что производительность во время выполнения приносится в жертву удобочитаемости. В большинстве случаев это стоящая жертва, потому что потери времени выполнения незначительны. Однако в критически важном для производительности коде вам может потребоваться профилирование различных решений.1 Вы можете увидеть это в спецификации C # :
Вы также можете проверить это с помощью небольшого кода:
источник
String.Format()
Если бы ваша строка была более сложной со многими объединяемыми переменными, я бы выбрал string.Format (). Но для размера строки и количества конкатенируемых переменных в вашем случае я бы выбрал вашу первую версию, она более спартанская .
источник
Я взглянул на String.Format (используя Reflector), и он фактически создает StringBuilder, а затем вызывает для него AppendFormat. Таким образом, это быстрее, чем concat для нескольких перемешиваний. Самым быстрым (я считаю) было бы создание StringBuilder и выполнение вызовов Append вручную. Конечно, количество «многих» остается только гадать. Я бы использовал + (на самом деле, потому что я в основном программист VB) для чего-то столь же простого, как ваш пример. По мере усложнения я использую String.Format. Если есть МНОГО переменных, я бы выбрал StringBuilder и Append, например, у нас есть код, который строит код, там я использую одну строку фактического кода для вывода одной строки сгенерированного кода.
Кажется, есть некоторые предположения о том, сколько строк создается для каждой из этих операций, поэтому давайте рассмотрим несколько простых примеров.
«C» - это уже строка.
rowIndex.ToString () создает другую строку. (@manohard - упаковки rowIndex не произойдет)
Затем мы получаем финальную строку.
Если взять пример
тогда у нас есть "C {0}", поскольку строка
rowIndex помещается в коробку для передачи в функцию.
Создается новый конструктор строк. В построителе строк вызывается
AppendFormat - я не знаю подробностей о том, как работает AppendFormat, но допустим, что это сверхэффективный, ему все равно придется преобразовывать упакованный rowIndex в строку.
Затем преобразуйте конструктор строк в новую строку.
Я знаю, что StringBuilders пытается предотвратить создание бессмысленных копий памяти, но String.Format по-прежнему вызывает дополнительные накладные расходы по сравнению с простой конкатенацией.
Если мы теперь возьмем пример с еще несколькими строками
у нас есть 6 строк для начала, которые будут одинаковыми для всех случаев.
Используя конкатенацию, мы также получаем 4 промежуточные строки плюс окончательный результат. Это те промежуточные результаты, которые исключаются с помощью String, Format (или StringBuilder).
Помните, что для создания каждой промежуточной строки предыдущая должна быть скопирована в новую ячейку памяти, это не просто выделение памяти, которое потенциально может быть медленным.
источник
Мне нравится String.Format, потому что он может сделать ваш форматированный текст намного проще для просмотра и чтения, чем встроенная конкатенация, а также он гораздо более гибкий, позволяя вам форматировать ваши параметры, однако для короткого использования, такого как ваш, я не вижу проблем с конкатенацией.
Для конкатенации внутри циклов или в больших строках всегда следует пытаться использовать класс StringBuilder.
источник
Этот пример, вероятно, слишком тривиален, чтобы заметить разницу. Фактически, я думаю, что в большинстве случаев компилятор может вообще оптимизировать любую разницу.
Однако, если бы мне пришлось угадывать, я бы дал
string.Format()
преимущество для более сложных сценариев. Но это скорее инстинктивное ощущение, что, вероятно, лучше будет работать с использованием буфера вместо создания нескольких неизменяемых строк, а не на основе каких-либо реальных данных.источник
Я согласен со многими пунктами выше, еще один момент, который, как мне кажется, следует упомянуть, - это ремонтопригодность кода. string.Format позволяет упростить изменение кода.
т.е. у меня есть сообщение
"The user is not authorized for location " + location
или"The User is not authorized for location {0}"
если бы я когда-нибудь хотел изменить сообщение, чтобы сказать:
location + " does not allow this User Access"
или"{0} does not allow this User Access"
со строкой. Отформатировать все, что мне нужно сделать, это изменить строку. для конкатенации я должен изменить это сообщение
при использовании в нескольких местах можно сэкономить время.
источник
У меня создалось впечатление, что string.format был быстрее, кажется, в этом тесте в 3 раза медленнее
string.format занял 4,6 секунды, а при использовании «+» - 1,6 секунды.
источник
"1" + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9" + "10"
один строковый литерал, поэтому строка становится"12345678910" + i
быстрее предыдущейstring.Format(...)
string.Format, вероятно, является лучшим выбором, когда шаблон формата ("C {0}") хранится в файле конфигурации (например, Web.config / App.config)
источник
Я провел небольшое профилирование различных строковых методов, включая string.Format, StringBuilder и конкатенацию строк. Конкатенация строк почти всегда превосходила другие методы построения строк. Итак, если производительность является ключевым фактором, то это лучше. Однако, если производительность не критична, я лично считаю, что string.Format легче использовать в коде. (Но это субъективная причина) Однако StringBuilder, вероятно, наиболее эффективен в отношении использования памяти.
источник
Я предпочитаю String.Format по производительности
источник
Объединение строк требует больше памяти по сравнению с String.Format. Поэтому лучший способ объединить строки - использовать String.Format или System.Text.StringBuilder Object.
Возьмем первый случай: «C» + rowIndex.ToString () Предположим, что rowIndex является типом значения, поэтому метод ToString () должен преобразовать значение в String, а затем CLR создает память для новой строки с обоими включенными значениями.
Где, как string.Format ожидает параметр объекта и принимает rowIndex как объект и преобразует его в строку, внутренне извне, будет Boxing, но он является внутренним, а также не займет столько памяти, как в первом случае.
Думаю, для коротких струн это не имеет большого значения ...
источник