.NET Framework 1.1 Performance Guidelines - String Operations

From Guidance Share

Jump to: navigation, search

- J.D. Meier, Srinath Vasireddy, Ashish Babbar, Rico Mariani, and Alex Mackman


Contents

Avoid Inefficient String Concatenation

Excessive string concatenation results in many allocation and deallocation operations, because each time you perform an operation to change the string, a new one is created and the old one is subsequently collected by the garbage collector.

  • If you concatenate string literals, the compiler concatenates them at compile time.
     //'Hello' and 'world' are string literals
     String str = "Hello" + "world";
  • If you concatenate nonliteral strings, CLR concatenates them at run time. So using the + operator creates multiple strings objects in the managed heap.

* Use StringBuilder for complex string manipulations and when you need to concatenate strings multiple times.

     // using String and '+' to append
     String str = "Some Text";
     for ( ... loop several times to build the string ...) {
       str = str + " additional text ";
     }
     // using String and .Append method to append
     StringBuilder strBuilder = new StringBuilder("Some Text ");
     for ( ... loop several times to build the string ...) {
       strBuilder.Append(" additional text ");
     }


Use + When the Number of Appends Is Known

If you know the number of appends to be made and you are concatenating the strings in one shot, prefer the + operator for concatenation.

String str = str1+str2+str3;

If you concatenate the strings in a single expression, only one call to String.Concat needs to be made. It results in no temporary strings (for partial combinations of the strings to be concatenated).

Note You should not be using + on strings inside a loop or for multiple iterations. Use StringBuilder instead.


Use StringBuilder When the Number of Appends Is Unknown

If you do not know the number of appends to be made, which might be the case when iterating through a loop or building dynamic SQL queries, use the StringBuilder class as shown in the following code sample.

for (int i=0; i< Results.Count; i++)
{
  StringBuilder.Append (Results[i]);
}  

The StringBuilder class starts with a default initial capacity of 16. Strings less than the initial capacity are stored in the StringBuilder object.

The initial capacity of the buffer can be set by using the following overloaded constructor.

public StringBuilder (int capacity);

You can continue to concatenate without additional allocations until you consume the preallocated buffer. As a result, using a StringBuilder object is often more efficient than using String objects for concatenation. If you concatenate further, the StringBuilder class creates a new buffer of the size equal to double the current capacity.

So if you start with a StringBuilder of size 16 and exceed the limit, the StringBuilder allocates a new buffer of size 32 and copies the old string to the new buffer. The old buffer is inaccessible and becomes eligible for garbage collection.

Note You should always try to set the initial capacity of the StringBuilder to an optimum value to reduce the cost of new allocations. To determine the optimum value for your case, the best way is to track the memory consumption by using the CLR profiler. For more information about how to use CLR profiler, see "How To: Use CLR Profiler" at http://msdn.microsoft.com/library/en-us/dnpag/html/scalenethowto13.asp


Treat StringBuilder as an Accumulator

You can treat StringBuilder as an accumulator or reusable buffer. This helps avoid the allocations of temporary strings during multiple append iterations. Some of the scenarios where this helps are as follows:

  • Concatenating strings. You should always prefer the following approach to string concatenation when using StringBuilder.
     StringBuilder sb;
     sb.Append(str1);
     sb.Append(str2);
     Use the preceding code rather than the following.
     sb.Append(str1+str2);

This is because you do not need to make the temporary str1+str2 to append str1 and then str2.

  • Concatenating the strings from various functions. An example of this is shown in the following code sample.
     StringBuilder sb;
     sb.Append(f1(…));
     sb.Append(f2(…)); 
     sb.Append(f3(…));

The preceding code snippet results in temporary string allocations for the return values by the functions f1 (...), f2 (…), f3 (…). You can avoid these temporary allocations by using the following pattern.

     void f1( sb,…);
     void f2( sb,…);
     void f3( sb,…);

In this case, the StringBuilder instance is directly passed as an input parameter to the methods. sb.Append is directly called in the function body, which avoids the allocation of temporary strings.


Use the Overloaded Compare Method for Case-Insensitive String Comparisons

Carefully consider how you perform case-insensitive string comparisons. Avoid using ToLower as shown in the following code because you end up creating temporary string objects.

// Bad way for insensitive operations because ToLower creates temporary 
strings
String str="New York";
String str2 = "New york";
if (str.ToLower()==str2.ToLower())
  // do something

The more efficient way to perform case-insensitive string comparisons is to use the Compare method.

str.Compare(str,str2,false);

Note The String.Compare method uses the info in the CultureInfo.CompareInfo property to compare culture-sensitive strings.

Personal tools