19

I have a loop where i create some string value based on certain conditions. I did place StringBuilder object outside of the loop and each time i have new row in loop i need to clear StringBuilder appended values for this row.

How do i clear those?

        StringBuilder sb = new StringBuilder();

        foreach (DataRow row in recipientsList.Rows)
        {
            sb.Length = 0;
            sb.Append("<ul>");
            if (row["needsToActivate"] == "1")
            {
                sb.AppendFormat("<li>{0}</li>", getUsersWithoutActivationTemplate());
            }
            if (row["needsToEnterSite"] == "1")
            {
                sb.AppendFormat("<li>{0}</li>", getUsersWithoutEnteringWebsiteForTwoWeeksTemplate());
            }
            if (row["needsPicture"] == "1")
            {
                sb.AppendFormat("<li>{0}</li>", getUsersWithoutPicturesTemplate());
            }
            if (row["needsText"] == "1")
            {
                sb.AppendFormat("<li>{0}</li>", getUsersWithoutTextTemplate());
            }
            if (row["needsCharacteristic"] == "1")
            {
                sb.AppendFormat("<li>{0}</li>", getUsersWithoutCharateristicsTemplate());
            }
            if (row["needsHobby"] == "1")
            {
                sb.AppendFormat("<li>{0}</li>", getUsersWithoutHobbiesTemplate());
            }
            sb.Append("</ul>");
}

Code with accepted answer;

Răzvan Flavius Panda
  • 21,730
  • 17
  • 111
  • 169
eugeneK
  • 10,750
  • 19
  • 66
  • 101

7 Answers7

53

You can simply;

sb.Length = 0;
Alex K.
  • 171,639
  • 30
  • 264
  • 288
  • exactly what i needed. I did almost use sb.Remove() which complicates the issue. – eugeneK Jul 12 '10 at 09:42
  • 2
    you can use this : sb.Remove(0, sb.Length); – AminM Aug 19 '12 at 17:13
  • 3
    It is not the best idea when you are working with very long strings. It can cause OOM exception. More explanation is provided on MSDN: https://social.msdn.microsoft.com/Forums/en-US/db04ba8c-e13e-4d41-89a2-f5601ec3e0ae/outofmemoryexception-setting-stringbuilder-length-to-0?forum=vbgeneral – Szymon Knop Feb 03 '15 at 09:48
  • 1
    It is correct to set Length=0 to empty a StringBuilder but keeping its memory. But when using StringBuilder.Insert(), this will not work. The Insert() will add more memory to the Stringbuilder, even if there is plenty of free memory in the StringBuilder. If the StringBuilder is repeatedly inserted and cleared, one gets an Out Of Memory exception finally. See my post: http://stackoverflow.com/questions/29574469/memory-leak-in-stringbuilder-when-using-insert-and-clear – Peter Huber Apr 13 '15 at 02:33
13

StringBuilder.Clear(); is what you want.

PhilPursglove
  • 12,511
  • 5
  • 46
  • 68
4

Set Length to 0, or in .Net 4 I believe you can call the new Clear() method.

Scott
  • 121
  • 1
  • 6
3

Assuming you define your StringBuilder like this: StringBuilder sb = new StringBuilder();

You can do any of the following:

Call the Clear method:

for (int i = 0; i < 100; i++)
{
    sb.Clear();
    .. your code here ..
}

Set the length to zero:

for (int i = 0; i < 100; i++)
{
    sb.Length = 0;
    .. your code here ..
}

Set it to a new object:

for (int i = 0; i < 100; i++)
{
    sb = new StringBuilder();
    .. your code here ..
}
Jonathan
  • 25,873
  • 13
  • 66
  • 85
  • That last one rather defeats the purpose of using StringBuilder in the first place... – codekaizen Jul 12 '10 at 09:38
  • 3
    @codekaizer: No, that last one is probably just as efficient as re-using the thing. The real use of the SB is what happen in the rest of the loop. – H H Jul 12 '10 at 09:57
3

You can re-use a StringBuilder (with .Clear() or .Length = 0) but if you really want to optimize you should try to estimate the final length. If this grows a little each iteration, re-using could be slower (use more mem) than creating a new one each time.

foreach (DataRow row in recipientsList.Rows)
{
    int estimatedLength = 5000; // maybe a calculation based on row-data
    StringBuilder sb = new StringBuilder(estimatedLength);
    ....

}

So while the answers here about how to do it are correct, the best advice is not to do it . It is a micro-optimization, and you don't need the very small gains here and you don't want the (small) extra complications. You could optimize a little here if the resulting string is very large but certainly don't make this a habit.

H H
  • 263,252
  • 30
  • 330
  • 514
  • length is eight at max, could be lower. So you're saying that if i assign default length i don't need to sb.Length=0 or it will just create smaller object and reduce time? – eugeneK Jul 12 '10 at 10:14
  • If I look at those AppendFormat() call your length will be a lot greater than eight. But yes, use a good estimate for the expected length and don't try to re-use like this. – H H Jul 12 '10 at 10:20
  • i have 8 Append methods it supposed to be the length or length of largest string appended? – eugeneK Jul 12 '10 at 10:38
  • @eugeneK: No, you need an estimate of the final result, __sum__ of all strings. Round up liberally. – H H Jul 12 '10 at 10:44
  • Thanks will combine your technique with setting length to 0. – eugeneK Jul 12 '10 at 10:55
0

I faced similar issue.

This trick worked for me

sb.Replace(sb.ToString(), "");

This code will replace entire string with "".

0

What I learned is

sb.Length = 0;

But my answer includes a hint on how to use StringBuilder without fragmenting memory. You're being careful to set the length to zero and reuse it, so you're not reallocating it all the time. Why not go a step further, and reduce fragmentation or frequent allocations?

StringBuilder sb = new System.Text.StringBuilder(22_000); // preallocate ~20K

If you can pretty much tell how much space you should need, consider allocating the space the StringBuilder is going to use up-front. There is a reason why the constructor allows you to specify how much space to allocate -- it improves performance. One allocation all-at-once should be faster than lots of little allocations interspersed with others.

So, I'll run some data through the code, look at the StringBuilder size, multiply by some factor, and put that as an initial allocation size for the StringBuilder.