Вопрос

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

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

return sb;

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

return sb.ToString();

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

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

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

Это было полезно?

Решение

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

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

Тем не менее.Если вы посмотрите на StringBuilder.Струна с отражателем:

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-е if).

Обновить

Система.String - это класс, что означает, что это ссылочный тип (в отличие от типа значения), поэтому "string foo;" по сути, является указателем.(Когда вы передаете строку в метод, он передает указатель, а не копию.) Система.Строка изменяема внутри mscorlib, но неизменяема вне его, именно так StringBuilder может манипулировать строкой.

Поэтому, когда вызывается toString(), он возвращает свой внутренний строковый объект по ссылке.На данный момент вы не можете изменить его, потому что ваш код находится не в mscorlib.Установив для поля m_currentThread значение ноль, любые дальнейшие операции с StringBuilder приведут к копированию объекта string, чтобы его можно было изменить и не изменять объект string, который он вернул в 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 - "Привет, мир".

Проясняет ли это всю проблему возврата / ссылки?

Другие советы

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

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

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

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

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

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

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

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

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

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

return sb.ToString();

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top