String или StringBuilder возвращаемые значения? - PullRequest
17 голосов
/ 07 мая 2009

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

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

return sb;

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

return sb.ToString();

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

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

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

Ответы [ 11 ]

22 голосов
/ 07 мая 2009

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

Относительно эффективности. Поскольку это неопределенный / общий вопрос без каких-либо подробностей, я думаю, что изменчивость против неизменности важнее производительности. Изменчивость - это проблема 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-ую, если).

UPDATE

System.String - это класс, который означает, что это ссылочный тип (в отличие от типа значения), поэтому "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».

Это проясняет весь вопрос возврата / ссылки?

5 голосов
/ 07 мая 2009

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

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

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

3 голосов
/ 07 мая 2009

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

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

3 голосов
/ 07 мая 2009

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

1 голос
/ 07 мая 2009

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

1 голос
/ 07 мая 2009

Так как вы больше не будете его изменять

return sb.ToString();

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

1 голос
/ 07 мая 2009

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

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

1 голос
/ 07 мая 2009

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

1 голос
/ 07 мая 2009

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

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

0 голосов
/ 07 мая 2009

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

...