SoFunction
Updated on 2025-03-06

How to use string String correctly in C#

Preface

C# provides a relatively comprehensive string processing method, and many functions are encapsulated to provide great convenience for our programming work. It is the most commonly used string operation class, which can help developers complete most of the string operation functions and is easy to use.

Strings are the most frequently used basic data type in all programming languages. If used carelessly, unnecessary memory overhead will be caused, and the price will be paid for it.

To optimize this type, start from the following two points:

1. Pack as little as possible

2. Avoid allocating extra memory space

Let’s start with the first point of packing, and check the following code:

 //The code that occurs for packing String boxOperate = "test" + 4.5f;

The IL code in the intermediate language is as follows:

 IL_0000: nop
 IL_0001: ldstr "test"
 IL_0006: ldc.r4 4.5
 IL_000b: box [mscorlib]
 IL_0010: call string [mscorlib]::Concat(object, object)
 IL_0015: stloc.0
 IL_0016: call valuetype [mscorlib] [mscorlib]::ReadKey()
 IL_001b: pop
 IL_001c: ret

It is not difficult to see that the above code has a boxing operation (box in the IL code). The reason why boxing has performance losses is because it needs to complete the following three steps:

1. First, memory will be allocated in the managed heap for the value type. In addition to the memory allocated by the value type itself, the total memory must be added to the memory occupied by the type object pointer and the synchronous block index.

2. Copy the value of the value type into the newly allocated heap memory.

3. Return the address of an object that has become a reference type.

Let's look at the following code:

//No boxing code occurs String boxOperate = "test" + ();

The IL code in the middle is as follows:

 IL_0000: nop
 IL_0001: ldstr "test"
 IL_0006: ldc.r4 4
 IL_000b: stloc.1
 IL_000c:  1
 IL_000e: call instance string [mscorlib]::ToString()
 IL_0013: call string [mscorlib]::Concat(string, string)
 IL_0018: stloc.0
 IL_0019: call valuetype [mscorlib] [mscorlib]::ReadKey()
 IL_001e: pop
 IL_001f: ret

As mentioned above, no packing operation occurred, but the result was what we wanted. The reason is that () this line of code does not have boxing behavior, but is actually called the ToString() method of integer type, and its prototype is as follows:

 public override string ToString(){
  return Number.FormatInt32(m_value, null, );
 }

Some people may ask, is the number.Format_XXX method in the prototype boxing behavior? In fact, the Number.Format_XXX method is an unmanaged method with a prototype as follows:

[MethodImpl(), SecurityCritical]
public statuc extern string FormatInt32(int value, string format,NumberFormatInfo info);

It completes the Int32 to String conversion by directly manipulating memory, which is much more efficient than boxing. Therefore, when using other value reference types to strings to convert them than to complete stitching, we should avoid using the operator "+" to complete it, but should use the value reference type to provide the ToString method.

Some people may ask: Even if the method provided by FCL does not have boxing behavior, in other cases, will the FCL method contain boxing behavior? It may exist, so I recommend: When writing code, try to avoid unnecessary packing code.

 

The second aspect: Avoid allocating additional space. For CLR, a String object (a string object) is a very special object, and it cannot be changed once it is assigned (in memory). Calling any method in the class or performing any operation ('='assignment,'+'spherding, etc.) at runtime will create a new string object in memory, which also means allocating new memory space for the new object. The following code will cause additional overhead.

private static void Test(){
 String str1 = "aa";
  str1 = str1 + "123" + "345";
   //The above code creates 3 String objects and executes the method once.}

In the following code, the string will not splice the string at runtime, but will directly generate a string at compile time.

private static void Test()
{
String str= "aa" + "123" + "345";//Equivalent String str= "aa123345";}

private static void Test2()
{
const String str = "aa";
String newStr = "123" + str;
//Because str is a constant, the code is equivalent to String newStr = "123" + "aa";//The final equivalent is String newStr = "123aa";}

Since using classes will cause significant performance losses in some cases, Microsoft also provides a type StringBuilder to make up for the shortcomings of String.

StringBuilder does not recreate a String object, its efficiency comes from pre-allocating memory in an unmanaged way. If the StringBuilder does not define the length first, the default allocated length is 16. When the length of StringBuilder is greater than 16 and less than 32, StringBuild will reallocate memory again to make it a multiple of 16. StringBuilder reallocates memory according to the last capacity doubling. Note: The length specified by StringBuilder should be appropriate. It is too small and requires frequent allocation of memory; it is too large and wastes memory space.

The following are examples:

private static String Test3()
  {
   String a = "t";
   a += "e";
   a += "s";
   a += "t";
   return a;
  }
  private static String Test4()
  {
   String a = "t";
   String b = "e";
   String c = "s";
   String d = "t";
   return a + b + c + d;
  }
  //The above two efficiency is not efficient.  Don't think that the former creates fewer string objects than the latter. In fact, the string objects created by the two are equal.  //And the former has been carried out3Method calls,Two more times than the latter。

To complete the runtime string stitching (note: it is runtime), it is better to use the StringBuilder type, the code is as follows:

private static String Test5()
  {
   String a = "t";
   String b = "e";
   String c = "s";
   String d = "t";
   StringBuilder sb = new StringBuilder(a);
   (b);
   (c);
   (d);
   return ();
   //Because it's about running time, there is no need to use the following code   //StringBuilder sb = new StringBuilder("t");
   //("e");
   //("s");
   //("t");
   //return ();
  }

Microsoft also provides another way to simplify this operation, i.e. use. The method uses StringBuilder internally to format strings, as shown in the following code:

private static String Test6()
{
  //For demonstration, define 4 variables  String a = "t";
  String b = "e";
  String c = "s";
  String d = "t";
  return ("{0}{1}{2}{3}", a, b, c, d);
}

Summarize:

When using String strings, boxing and "+" connection operations should be avoided as much as possible.

Okay, the above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.