2009-05-07 5 views
17

Если я строю строку с использованием объекта StringBuilder в методе, имеет смысл:String или StringBuilder возвращают значения?

Возвращает объект StringBuilder и позволяет вызывающему коду вызвать ToString()?

return sb; 

ИЛИ Верните строку, вызвав ToString() самостоятельно.

return sb.ToString(); 

Я думаю, что это имеет значение, если мы возвращаем небольшие или большие строки. Что было бы уместно в каждом случае? Заранее спасибо.

Редактировать: Я не планирую дальше изменять строку в вызывающем коде, но хорошая точка Колин Бернетт.

В основном, более эффективно возвращать объект StringBuilder или строку? Будет ли ссылка на строку возвращена или копия?

ответ

21

Верните StringBuilder, если вы собираетесь изменить строку, иначе верните строку. Это вопрос API.

Что касается эффективности. Поскольку это неопределенный/общий вопрос без каких-либо особенностей, я думаю, что mutable vs. immutable более важен, чем производительность. Mutability - это проблема API, позволяющая вашему API возвращать модифицируемые объекты. Длина строки не имеет к этому отношения.

указано. Если вы посмотрите на StringBuilder.ToString с отражателем:

public override string ToString() 
{ 
    string stringValue = this.m_StringValue; 
    if (this.m_currentThread != Thread.InternalGetCurrentThread()) 
    { 
     return string.InternalCopy(stringValue); 
    } 
    if ((2 * stringValue.Length) < stringValue.ArrayLength) 
    { 
     return string.InternalCopy(stringValue); 
    } 
    stringValue.ClearPostNullChar(); 
    this.m_currentThread = IntPtr.Zero; 
    return stringValue; 
} 

Вы можете видеть, что это может сделать копию, но если вы измените его с StringBuilder, то он будет делать копию, то (это то, что я могу сказать, точку m_currentThread - это потому, что Append проверяет это и копирует его, если он не соответствует текущему потоку).

Я думаю, что конец этого заключается в том, что если вы не изменяете StringBuilder, вы не копируете строку, а длина не имеет отношения к эффективности (если вы не нажмете на это 2-е, если).

ОБНОВЛЕНИЕ

System.String это класс, который означает, что он является ссылочным типом (в отличие от типа значения), так что «строка Foo;» по существу, является указателем. (Когда вы передаете строку в метод, она передает указатель, а не копию.) System.String изменена внутри mscorlib, но неизменна вне ее, а именно, как StringBuilder может манипулировать строкой.

Итак, когда вызывается ToString(), он возвращает свой внутренний строковый объект по ссылке. На данный момент вы не можете изменить его, потому что ваш код не находится в mscorlib. Установив поле m_currentThread равным нулю, любые дальнейшие операции над StringBuilder заставят его скопировать строковый объект, чтобы его можно было изменить и не изменять строковый объект, который он возвращал в ToString(). Рассмотрим это:

StringBuilder sb = new StringBuilder(); 
sb.Append("Hello "); 

string foo = sb.ToString(); 

sb.Append("World"); 

string bar = sb.ToString(); 

Если StringBuilder не сделать копию, то в конце Foo будет «Hello World», потому что StringBuilder изменил его. Но поскольку он сделал копию, тогда foo по-прежнему просто «Hello», а bar - «Hello World».

Означает ли это, что все возвращается/ссылка?

+0

@SkippyFire спрашивает об эффективности. –

+0

-1. Если вы собираетесь изменить строку, ее следует дополнительно модифицировать в рамках метода. Что делать, если этот метод вызывается из нескольких мест и изменяется логика манипуляции строкой? Было бы неплохо обновить логику в нескольких местах. –

+1

Ник, вы раскалываете волосы. Если это относится к классу и частному методу, вы можете очень хорошо передать StringBuilder ко многим методам для создания окончательной строки. Вы можете сделать то же самое, когда каждый метод возвращает строку и объединяет их. SkippyFire не был специфичен вообще в том, как это используется. Это довольно просто: если вам нужно изменить, то return mutable, если вам не нужно mutable, то не возвращайте mutable. –

5

Я не думаю, что производительность должна быть фактором в этом вопросе. В любом случае кто-то собирается называть sb.ToString(), чтобы вы могли попасть туда.

Важнейшим вопросом является то, что является намерением метода и цели. Если этот метод является частью построителя, вы можете вернуть построитель строк. В противном случае я бы вернул строку.

Если это часть открытого API, я бы склонялся к возврату строки вместо строителя.

+0

Вопрос эффективности заключается в том, если вы собираетесь изменить строку больше, тогда было бы лучше иметь ее уже в изменяемой форме (т. Е. StringBuilder), чтобы избежать копирования в новый StringBuilder для ее изменения. Просто потому, что где-то вниз по строке вы вызываете ToString, это не значит, что вы не хотите избегать промежуточного копирования. –

+1

@Colin Burnett, с точки зрения производительности, если требуется изменчивость, возвращение StringBuilder - практическое решение, но оно не очень хорошее. Предпочтительно переписывать вызывающего абонента для поддержки шаблона, который полностью создает объект и откладывает построение строки на один вызов. Есть два недостатка в возвращении StringBuilder, во-первых, он соединяет вас с деталями реализации. Во-вторых, он уклоняется от создания хорошего подхода к ООП, что будет препятствовать жизнеспособности решения как API (и блокирует вас процедурной реализацией). –

+0

Майкл, мой единственный момент в этом комментарии заключался в том, что «кто-то собирается называть sb.ToString() «отсутствует точка промежуточного копирования, которая повлияет на производительность. Иногда да, вы можете захотеть воспользоваться хитом ради лучшего API или быть мотивированным, чтобы найти решение, отличное от« string или StringBuilder ». –

3

Я бы сказал, что метод должен возвращать sb.ToString(). Если логика, связанная с созданием объекта StringBuilder(), должна измениться в будущем, мне будет понятно, что она будет изменена в методе не в каждом сценарии, который вызывает этот метод, а затем продолжает делать что-то еще.

0

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

Существуют и другие технические соображения, но это относится к проблемам самого высокого уровня.

1

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

Подумав об этом на данный момент, ответ намного яснее. Вопрос о том, что нужно вернуть, действительно отвечает на вопрос. Обратный объект должен быть строкой. Причина в том, что если вы задаете вопрос: «Есть ли причина возвращать объект StringBuilder, когда строка будет работать?» тогда ответ - нет. Если возникла причина, тогда возвращаемая строка не может быть и речи, потому что необходимы методы и свойства строкового конструктора.

1

Я думаю, что это зависит от того, что вы делаете со строкой, когда она покидает метод. Если вы собираетесь продолжить добавление к нему, вы можете захотеть вернуть строковый конструктор для большей эффективности. Если вы всегда будете называть его .ToString(), вы должны сделать это внутри метода для лучшей инкапсуляции.

1

Я бы вернул string практически во всех ситуациях, особенно если этот метод является частью общедоступного API.

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

1

Поскольку вы не собираетесь изменять его больше

return sb.ToString(); 

должен быть наиболее эффективным

1

Верните sb.ToString(). Ваш метод должен сосредоточиться только на том, что в руке (в этом случае построить мне строку), а не возвращаться для дальнейшей обработки IMO, вы можете столкнуться со всеми проблемами, с которыми он не будет удален.

3

StringBuilder - это деталь реализации вашего метода. Вы должны возвращать строку до тех пор, пока она не станет проблемой производительности, после чего вы должны изучить другой шаблон (например, visitor Pattern), который может помочь вам ввести косвенность и защитить вас от внутренних решений по внедрению.

Строки всегда хранятся в куче, поэтому у вас будет ссылка, если тип возврата - строка. Однако вы не можете рассчитывать на две одинаковые строки, чтобы иметь одинаковые ссылки. В общем, безопасно думать о строке, как если бы это был тип значения, даже если это фактически ссылочный тип.

+1

+1 для реализации детали –

0

Метод получил конкретную задачу, и его следует ожидать, чтобы завершить его и вернуть законченный результат, который не требует дальнейшей обработки. Верните только StringBuilder, когда вам это действительно нужно. В этом случае также добавьте что-то к имени метода, чтобы указать, что вы возвращаете что-то особенное.

Смежные вопросы