Почему конкатенация строк не преобразуется автоматически в StringBuilder в C#?

Возможный дубликат:
Почему String.Concat не оптимизирован для StringBuilder.Append?

Однажды я разглагольствовал о конкретном элементе управления Telerik своему другу. Я сказал ему, что создание дерева элементов управления заняло несколько секунд, и после профилирования я обнаружил, что оно использует конкатенацию строк в цикле вместо StringBuilder. После перезаписи заработало почти мгновенно.

Итак, мой друг услышал это и, похоже, был удивлен, что компилятор C# не выполняет это преобразование автоматически, как это делает компилятор Java. Читая многие ответы Эрика Липперта, я понимаю, что эта функция не вошла в историю, потому что не была сочтена достаточно достойной. Но если, гипотетически, затраты на его реализацию были бы небольшими, какое обоснование помешало бы это сделать?


person Roman Royter    schedule 03.02.2012    source источник
comment
Технически ничто не мешает вам выполнить эту оптимизацию, но учтите, что эти две операции семантически не эквивалентны. Объединение string возвращает новый объект string, который является результатом операции, а использование StringBuilder изменит существующий строковый объект. Необходимо выполнить анализ кода, чтобы убедиться, что вы никоим образом не полагаетесь на побочные эффекты конкатенации. В большинстве случаев это не проблема, которую невозможно решить, но опять же, в первую очередь не так уж сложно написать код правильно.   -  person Cody Gray    schedule 03.02.2012
comment
См. также blogs.msdn. com/b/ericlippert/archive/2011/07/19/   -  person SLaks    schedule 03.02.2012
comment
посмотрите также этот пост: pranayamr.blogspot .com/2011/02/   -  person Pranay Rana    schedule 03.02.2012


Ответы (2)


Но если, гипотетически, затраты на его реализацию были бы небольшими, какое обоснование помешало бы это сделать?

Похоже, вы предлагаете немного тавтологию: если нет причин не делать X, то есть ли причина не делать X? Нет.

Я не вижу большой ценности в знании ответов на гипотетические, контрфактуальные вопросы. Возможно, лучше задать вопрос о реальном мире:

Существуют ли языки программирования, использующие эту оптимизацию?

да. В JScript.NET мы обнаруживаем конкатенации строк в циклах, и компилятор превращает их в вызовы построителя строк.

Затем это может сопровождаться:

Каковы некоторые различия между JScript .NET и C#, которые оправдывают оптимизацию в одном языке, но не в другом?

Основное предположение JScript.NET заключается в том, что его программисты в основном будут программистами JavaScript, и многие из них уже создали библиотеки, которые должны работать в любой реализации ECMAScript. Эти программисты могут плохо знать платформу .NET, а даже если и знают, они не смогут использовать StringBuilder, не сделав код своей библиотеки непереносимым. Также разумно предположить, что программисты на JavaScript могут быть либо начинающими программистами, либо программистами, пришедшими в программирование по роду деятельности, а не по курсу компьютерных наук.

Программисты на C#, скорее всего, хорошо знают платформу .NET, пишут библиотеки, работающие с этой средой, и являются опытными программистами, понимающими, почему зацикленная конкатенация строк составляет O(n2) в простом коде. реализация. Им меньше нужна эта оптимизация, созданная компилятором, потому что они могут сделать это сами, если сочтут это необходимым.

Вкратце: возможности компилятора — это расход нашего бюджета на добавление ценности для клиента; вы получаете больше отдачи, добавляя эту функцию в JScript.NET, чем добавляя ее в C#.

person Eric Lippert    schedule 03.02.2012
comment
Спасибо за ответы. Однако я не предложил тавтологию. Иногда функции не добавляются по идеологическим причинам, а не только из-за чистой стоимости (на проектирование, реализацию, тестирование). Например, вы сами заявили, что C# не включает расширение .ForEach просто потому, что оно внесет ненужную двусмысленность. Затраты на добавление этого лайнера минимальны, и тем не менее их обоснование не связано с ними. Но я думаю, что ваш окончательный вывод является удовлетворительным аргументом для меня, чтобы использовать его с моим другом. - person Roman Royter; 03.02.2012
comment
@RomanR.: Я скептически отношусь к этому. Можете ли вы привести пример идеологического решения, которое на самом деле не является решением, основанным на затратах? - person Brian; 03.02.2012
comment
@Brian: пример RomanR хороший; мы могли бы сделать метод расширения ForEach для IEnumerable<T> по очень низкой цене и с некоторой выгодой, но, на мой взгляд, это не соответствует духу LINQ, который заключается в том, чтобы избежать побочных эффектов. Это пункты против выполнения этой функции. Есть, конечно, и бюджетный аргумент против этого, а именно альтернативная стоимость того, чтобы не сделать лучшую функцию. Но пункты против есть пункты против, и не все пункты против основаны на стоимости. - person Eric Lippert; 03.02.2012
comment
Лично мне не нравится метод расширения Foreach по тем же причинам, что и вам. Но проблема с тем, чтобы оставить его вне фреймворка, заключается в том, что теперь мы получаем множество тонко отличающихся сторонних версий, потому что многие люди думают, что это хорошая идея. Поэтому я считаю, что текущая ситуация хуже, чем включение ее в структуру. - person CodesInChaos; 03.02.2012
comment
Похоже, компилятор Java 8 выполняет эту оптимизацию: dzone.com/articles/ - person vkelman; 23.12.2016

Компилятор C# делает это лучше.

a + b + c компилируется в String.Concat(a, b, c), что быстрее, чем StringBuilder.
"a" + "b" компилируется непосредственно в "ab" (полезно для многострочных литералов).

Единственное место, где можно использовать StringBuilder, это многократное объединение внутри цикла; компилятор не может легко оптимизировать это.

person SLaks    schedule 03.02.2012
comment
Действительно ли это быстрее, независимо от размера и количества объединяемых строк? - person Shredderroy; 03.02.2012
comment
Это именно то, о чем идет речь в вопросе: объединение в цикле. - person Cody Gray; 03.02.2012
comment
@CodyGray: мне трудно поверить, что Java оптимизирует это. - person SLaks; 03.02.2012
comment
@Shredderroy: Да. Concat заранее знает размер, поэтому ему никогда не нужно перераспределять. Я не знаю, как это будет сравниваться с предварительно установленным размером StringBuilder; Я предполагаю, что Concat будет на минуту быстрее. - person SLaks; 03.02.2012
comment
Компилятор может легко оптимизировать это; это не сложная оптимизация для написания. Мы просто выбираем не делать этого. - person Eric Lippert; 03.02.2012