найкращий спосіб очистити вміст .NET StringBuilder


75

Я хотів би запитати, який, на вашу думку, найкращий спосіб (триває менше / споживає менше ресурсів) очистити вміст, щоб повторно використовувати StringBuilder. Уявіть такий сценарій:

StringBuilder sb = new StringBuilder();
foreach(var whatever in whateverlist)
{
  sb.Append("{0}", whatever);
}

//Perform some stuff with sb

//Clear stringbuilder here

//Populate stringbuilder again to perform more actions
foreach(var whatever2 in whateverlist2)
{
  sb.Append("{0}", whatever2);
}

І при очищенні StringBuilder я можу думати про дві можливості:

sb = new StringBuilder();

або

sb.Length = 0;

Який найкращий спосіб це очистити і чому?

Дякую.

РЕДАГУВАТИ: я працюю з поточною версією .NET 3.5.


4
Не відповідь, але цікаво прочитати: bobondevelopment.com/2007/06/11/…
Філіп Уоллес,

1
У чому причина не включення методу StringBuilder.Clear () як альтернативи?
Rune FS

@Rune: c # 4.0 ще не вийшов, це лише в 4.0. На MSDN написано: Підтримується: 4.
jcollum

мені пощастило, що вийшов c # 4.0 blogs.msdn.com/somasegar/default.aspx
Rune FS

2
Цікаво, чому Lengthможна писати, але немає властивості "Текст" для читання / запису? Висловлювання sb.Text = "";здається яснішим sb.Length = 0;, і Textвластивість також допоможе у загальному сценарії, коли в іншому випадку потрібно було б сказати sb.Length = 0; sb.Append(StuffToStartWith);.
supercat

Відповіді:


72

Якщо ви робите це в .NET 2.0 або 3.5, напишіть метод розширення, щоб зробити це так:

/// <summary>
///     Clears the contents of the string builder.
/// </summary>
/// <param name="value">
///     The <see cref="StringBuilder"/> to clear.
/// </param>
public static void Clear(this StringBuilder value)
{
    value.Length = 0;
    value.Capacity = 0;
}

Потім ви можете очистити це так:

someStringBuilder.Clear();

Потім, коли вийде 4.0, ви можете відмовитись від методу розширення на користь версії 4.0.

ОНОВЛЕННЯ : Напевно, не є гарною ідеєю встановлювати ємність на нуль. Це гарантуватиме перерозподіл, коли ви додасте до конструктора, якщо ви повторно використовуєте той самий екземпляр. Однак пам'ять у екземплярі конструктора не звільняється, поки ви не встановите для Ємності дуже маленьке значення (наприклад, 1). Значенням властивості Capacity за замовчуванням є 16. Можливо, ви захочете використати 16 або (хоча це менш ефективно) встановити ємність двічі:

  • Встановіть його на 1 або нуль, щоб очистити пам’ять
  • Встановіть для початкового значення ємності (яке може відрізнятися від 16), щоб відновити його.

Акуратний метод. Саме те, що я шукав.
abhi

15
Я не рекомендував би очищати ємність, за винятком випадків, коли StringBuilderвідомо, що в них містилося щось надзвичайно велике. Особливо в попередніх версіях .net, якщо один буде багаторазово будувати рядки довжиною понад 42 500 символів, очищення буфера після кожного рядка призведе до виділення додаткових об’єктів у купі великих об’єктів кожного разу, коли буфер повинен повторно зростати. Це погана річ.
supercat

2
Цікавою ідеєю є встановлення ємності на 0. Коли ви просто використовуєте Clear або просто встановлюєте довжину 0, може статися витік пам'яті при повторному використанні Insert (), оскільки ємність постійно зростає, незважаючи на Clear. (див. моє запитання: stackoverflow.com/questions/29574469/…
Пітер Хубер

29

У .NET 4.0 ви можете телефонувати, sb.Clear()але в старих версіях ви повинні встановити sb.Length = 0.

Clear()Метод був доданий в .NET 4.0.


15
Якщо ви повторно використовуєте його, чи не хочете ви повторно використовувати буфер?
GraemeF

2
залежить від дисперсії того, наскільки великий рядок створений вперше порівняно із рядком, створеним вдруге .. Або, принаймні, я б так думав
Earlz

16

Створіть новий StringBuilder. Старий підтримує пов’язані з ним ресурси (наприклад, буфер максимальної довжини), які найкраще - просто зібране сміття.


11

Я думаю, ви робите передчасну оптимізацію.

Б'юся об заклад, що це sb.Length=0;буде найшвидше, щоб уникнути створення іншого об'єкта та розміщення іншого об'єкта в стороні для GC, щоб врешті-решт зібрати.

Я думаю, що створення нового StringBuilder було б найкращим варіантом для проблем з пам'яттю. і налаштування sb.Lengthбуло б найкращим пострілом для проблем зі швидкістю ..


11

Із вмісту спільноти на MSDN :

Для ефективного очищення вашого конструктора рядків, не знищуючи його, використовуйте:

 someStringBuilder.length = 0;
 someStringBuilder.capacity = 0;

Це знищує як його вміст, так і змінює його до нуля. Як зазначалося вище, розмір може впливати на додатки менших розмірів.


5

У .NET Framework в StringBuilderкласі було представлено 4 нові методи . Назва методу - "Очистити". Цей метод допомагає очистити або видалити значення або дані з StringBuilderоб’єктів.

Ось приклад для цього.

    System.Text.StringBuilder objSB = new System.Text.StringBuilder();
    //Append values
    objSB.Append("This is .Net Blog.");
    objSB.Append("You can get latest C# Tips over here.");

    //Display on screen
    Response.Write(objSB.ToString());
    Response.Write("<br/><br/>");

    //Clear object using Clear method
    objSB.Clear();

    //Append another values
    objSB.Append("This blog is very useful for .Net Beginners");

    Response.Write("After Clear<br/><br/>");
    //Display on screen
    Response.Write(objSB.ToString());

2

Якщо ви хочете зменшити використання пам'яті, я б використовував CLR Profiler, щоб перевірити, скільки пам'яті використовують ваші об'єкти StringBuilder протягом свого життєвого циклу, використовуючи методи, описані іншими вище. Тоді ви можете переконатись, що обраний вами варіант підходить для ваших потреб, і звільняє ресурси, які вам потрібні.


1

Я б сказав, що найкращий спосіб це очистити - це використовувати sb = new StringBuilder();. З огляду на це, я думаю, що було б ще краще, якби ви взагалі створили новий об’єкт конструктора рядків.

РЕДАГУВАТИ

Сподіваюся, це само собою зрозуміле, що це найкраще рішення.

public StringBuilder MakeString(IEnumerable<CoolType> list)
{
    StringBuilder sb = new StringBuilder();

    foreach(var whatever in list)
    {
        sb.Append("{0}", whatever);
    }
}

var sb = MakeString(whateverList);
// Do stuff
// Clear stuff
sb = MakeString(whateverList2);

5
sb = new StringBuilder () Створює новий об'єкт конструктора рядків.
Філіп Уоллес,

Це робить НЕ створювати новий об’єкт конструктора рядків взагалі.
Пол Соньє,

Я думаю, що Метт означає оголосити нову змінну ДЛЯ нової StringBuilder.
Dan Tao

На жаль, для уточнення я рекомендую зробити щось подібне: var wellNamedStringBuilder = new StringBuilder ();
Метт Гранде

1

C # У двох словах Щоб очистити вміст a StringBuilder, є два способи:

  1. Встановіть його Lengthна нуль:

    Встановлення StringBuilder's Lengthдля zeroне зменшує його внутрішню ємність. Отже, якщо StringBuilder раніше містив один мільйон символів, він буде продовжувати займати близько 2 Мб пам'яті після обнулення його довжини.

  2. Застосуйте новий:

    Якщо ви хочете release the memory, ви повинні створити новий StringBuilder і дозволити старому вийти з поля дії (і збирати сміття), за допомогою цього підходу ви можете вирішити попередню проблему елемента.


0

Просто зателефонуйте методу Clear (), просто встановивши довжину = 0. Ми також можемо встановити Capacity = 0, якщо хочемо заощадити пам'ять

public StringBuilder Clear() {
        this.Length = 0;
        return this;
 }

Посилання: у referenceource.microsoft.com


0
// P.S. to be ultra efficient 
// make a good guess at the initial allocation too !!!!
int PerWhatever_SizeEstimate = 4; // a guess of average length... you known your data
StringBuilder sb = new StringBuilder( whateverlist.Length * PerWhatever_SizeEstimate);

// reallocation needed? 
// if you want to be efficient speed and memory wise... 
sb.Length = 0;  // rest internal index but don't release/resize memory
// if a ...BIG... difference in size
if( whatever2.Length < whatever.Length * 2/3  
 || whatever2.Length > whatever.Length * 1.5)
{
    //scale capacity appropriately
    sb.Capaciy = sb.Capacity * whatever2.Length / whatever.Length;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.