- Introduction
- Creating and Using String Objects
- Formatting Strings
- Accessing Individual String Characters
- Analyzing Character Attributes
- Case-Insensitive String Comparison
- Working with Substrings
- Using Verbatim String Syntax
- Choosing Between Constant and Mutable Strings
- Optimizing StringBuilder Performance
- Understanding Basic Regular Expression Syntax
- Validating User Input with Regular Expressions
- Replacing Substrings Using Regular Expressions
- Building a Regular Expression Library
3.8. Choosing Between Constant and Mutable Strings
You want to choose the correct string data type to best fit your current application design.
Technique
If you know a string's value will not change often, use a string object, which is a constant value. If you need a mutable string, one that can change its value without having to allocate a new object, use a StringBuilder.
Comments
Using a regular string object is best when you know the string will not change or will only change slightly. This change includes the whole gamut of string operations that change the value of the object itself, such as concatenation, insertion, replacement, or removal of characters. The Common Language Runtime (CLR) can use certain properties of strings to optimize performance. If the CLR can determine that two string objects are the same, it can share the memory that these string objects occupy. These strings are then known as interned strings. The CLR contains an intern pool, which is a lookup table of string instances. Strings are automatically interned if they are assigned to a literal string within code. However, you can also manually place a string within the intern pool by using the Intern method. To test whether a string is interned, use the IsInterned method, as shown in Listing 3.7.
Listing 3.7 Interning a String by Using the Intern Method
using System; namespace _7_StringBuilder { /// <summary> /// Summary description for Class1. /// </summary> class Class1 { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { string sLiteral = "Automatically Interned"; string sNotInterned = "Not " + sLiteral; TestInterned( sLiteral ); TestInterned( sNotInterned ); String.Intern( sNotInterned ); TestInterned( sNotInterned ); } static void TestInterned( string str ) { if( String.IsInterned( str ) != null ) { Console.WriteLine( "The string \"{0}\" is interned.", str ); } else { Console.WriteLine( "The string \"{0}\" is not interned.", str ); } } } }
A StringBuilder behaves similarly to a regular string object and also contains similar method calls. However, there are no static methods because the StringBuilder class is designed to work on string instances. Method calls on an instance of a StringBuilder object change the internal string of that object, as shown in Listing 3.8. A StringBuilder maintains its mutable appearance by creating a buffer that is large enough to contain a string value and additional memory should the string need to grow.
Listing 3.8 Manipulating an Internal String Buffer Instead of Returning New String Objects
using System; using System.Text; namespace _7_StringBuilder { class Class1 { [STAThread] static void Main(string[] args) { string string1 = ""; String string2 = ""; Console.Write( "Enter string 1: " ); string1 = Console.ReadLine(); Console.Write( "Enter string 2: " ); string2 = Console.ReadLine(); BuildStrings( string1, string2 ); } public static void BuildStrings( string str1, string str2 ) { StringBuilder sb = new StringBuilder( str1 + str2 ); sb.Insert( str1.Length, " is the first string.\n" ); sb.Insert( sb.Length, " is the second string.\n" ); Console.WriteLine( sb ); } } }