C# String in Depth

C# String in Depth

In this article, I am going to discuss C# String in Depth with examples. Please read our previous article, where we discussed C# Data Types in detail. As a developer it is very important to understand the concept of C# strings and I am also sure you are using C# string in all of your projects. But there are many things that you should know from a performance point of view. So, as part of this article, we are going to discuss the following pointers in detail with examples.

  1. Strings are reference types
  2. Understanding the difference between string(small) vs String(Capital).
  3. Why strings are immutable?
  4. How we can improve performance using String intern?
  5. StringBuilder for concatenation.
  6. Why they made string as immutable.
Strings are reference types in C#:

C# strings are objects i.e. they are not normal data types. For example, if we define some variables using int or double data types as shown below,

Primitive Types are Struct in C#

Then if you right click on the data type and go the definition then you will see that they are struct as shown in the below image. Struct means they are value type.

Struct in C#

On the other hand if you define a variable with string data type as shown below.

string in C#

Then if you right click on the string data type and click on go to definition then you will see that it is a class. Class means reference data type.

Strings are reference type in C#

So, the first point that you need to remember is strings are reference type while other primitive data types are struct type.

String(Capital) vs string(small) in C#:

You can use the string in two ways. I.e. you can use the string using capital S or by using the small s as shown in the below image.

String(Capital) vs string(small) in C#

Now the question that should comes to your mind is what is the difference between these two (string vs String). Let’s understand this.

The small string is actually an alias of String (Capital string). If you right click on the small string and if you go to the definition then you will see that the actual class name is capital string i.e. String as shown in the below image.

what is the difference between string and String in C#

Note: You can use any one of them i.e. either string or String.

But as per the naming convention when you are creating a variable use the small string but whenever you want to invoke methods on string then use the capital string as shown in the below image.

The small string is actually an alias of Capital String

Strings are immutable in C#:

Before understanding strings are immutable, first we need to understand two terms i.e. Mutable and Immutable. Mutable means can be changed whereas Immutable means can not be changed. C# strings are immutable means C# strings cannot be changed. Let us understand this with an example.

Please have a look at the below image. When the first statement executed, it will create one object and assign the value DotNet. But when the second statement executed, it will not override the first object, it lets the first object to be their for garbage collection and creates a fresh object and assign the value Tutorials.

Strings are immutable in C#

So, when the above two statements executed, internally two memory locations are created. One with the value DotNet and the current one with the value Tutorials and the current one is going to be referred in the program. So, each time, you assign a new value to the string variable, a new object is created and this is the reason why strings are immutable.

But this is not the case with value type. For example, please have a look at the below two statements. When the first statement is executed one memory location is created and assign the value 100 and when the second statement executed it will not create a new memory location rather it will override the value of the same memory location.

Proves C# strings are immutable

Example to proves C# strings are immutable:

Let us see an example to understand this. Please copy and paste the following code. As you can see here we have a heavy for loop. As part of the Loop we assigning a value to the string str variable. Here, we are using GUID to generate a new value and each time it will create a new value and assign it to the str variable. Again, we are using Stopwatch to check how much time it took to execute the loop.

using System;
using System.Diagnostics;

namespace StringDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            string str = "";
            Console.WriteLine("Loop Started");
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            for (int i = 0; i < 30000000; i++)
            {
                 str = Guid.NewGuid().ToString();
            }
            stopwatch.Stop();

            Console.WriteLine("Loop Ended");
            Console.WriteLine("Loop Exceution Time in MS :" + stopwatch.ElapsedMilliseconds);

            Console.ReadKey();
        }
    }
}

Output: When you execute the program, you will get the following output. The time may vary in your machine.

Proves C# strings are immutable

As you can see in the above output, it approximately took 26000 milliseconds to execute the loop. Each time the loop executes, it create a fresh string object and assign the new value to it. This is because strings are immutable.

Example using integer:

In the following example, instead of string we are using an integer variable. As integer are not immutable, so it will not create fresh memory location each time the loop executes instead it will use the same memory location and update its value.

using System;
using System.Diagnostics;

namespace StringDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int ctr =0;
            Console.WriteLine("Loop Started");
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            for (int i = 0; i < 30000000; i++)
            {
                ctr = ctr + 1;
            }
            stopwatch.Stop();

            Console.WriteLine("Loop Ended");
            Console.WriteLine("Loop Exceution Time in MS :" + stopwatch.ElapsedMilliseconds);

            Console.ReadKey();
        }
    }
}

Output:

Example using integer

As you can see in the above output, it only took 84 milliseconds to execute the loop.

Example: String with Same value

As you can see in the below example, which is exactly same as the first example, but here instead of using GUID, we are assigning a fixed value to the string str variable.

using System;
using System.Diagnostics;

namespace StringDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            string str = "";
            Console.WriteLine("Loop Started");
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            for (int i = 0; i < 30000000; i++)
            {
                str ="DotNet Tutorials";
            }
            stopwatch.Stop();

            Console.WriteLine("Loop Ended");
            Console.WriteLine("Loop Exceution Time in MS :" + stopwatch.ElapsedMilliseconds);

            Console.ReadKey();
        }
    }
}

Output:

String Interning in C#

As you can see in the above output it only took 95 milliseconds. This is because in this case fresh objects are not created each time the loop executes. Now, the question that should comes to your mind is why? The answer is String intern. So, let us understand string interning in detail.

String Interning in C#:

The String Interning in C# is a process which uses the same memory location if the value is same. In our example, when the loop executes for the first time, it will create a fresh object and assign the value “DotNet Tutorials” to it. When the loop executes 2nd time, before creating a fresh object, it will check whether this “DotNet Tutorials” value is already there in the memory, if yes then it simply uses that memory location else it will create a new memory location. This is nothing but C# string interning.

So, if you are running a for loop and assigning the same value again and again, then it uses string interning to improve the performance. In this case rather than creating new object, it uses the same memory location.

StringBuilder for concatenation:

The C# string immutability behavior can be very very dangerous when it comes to string concatenation. Let us understand this with an example. In the below example, we are concatenating the string using the for loop.

using System;
using System.Diagnostics;

namespace StringDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            string str = "";
            Console.WriteLine("Loop Started");
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            for (int i = 0; i < 30000; i++)
            {
                str ="DotNet Tutorials" + str;
            }
            stopwatch.Stop();

            Console.WriteLine("Loop Ended");
            Console.WriteLine("Loop Exceution Time in MS :" + stopwatch.ElapsedMilliseconds);

            Console.ReadKey();
        }
    }
}

Output:

concatenation using string

As you can see in the above image, it took 5473 milliseconds to execute the loop. In order to understand how it executes the loop, please have a look at the below image. The loop execute the first time, it will create a new memory location and store the value “DotNet Tutorials”. For second time, it creates another fresh memory location (fresh object) and store the value “DotNet Tutorials DotNet Tutorials” and the first memory location will be go for garbage collection. And the same process will be continue i.e. each time the loop execute a new memory location will be created and previous ones will be go for garbage collection.

concatenation flow using C# string

In order to solve the above string concatenation problem, the .NET Framework provides StringBuilder class. As the name itself saying everything, the string builder class is used to build a string. If you use string builder then fresh objects are not going to created.

Example using StringBuilder:

In the following example we are using StringBuilder class to concatenate strings. Here, first we create an instance of StringBuilder class and then use the Append method to concatenate the string.

using System;
using System.Diagnostics;
using System.Text;

namespace StringDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder stringBuilder = new StringBuilder();
            Console.WriteLine("Loop Started");
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            for (int i = 0; i < 30000; i++)
            {
                stringBuilder.Append("DotNet Tutorials");
            }
            stopwatch.Stop();

            Console.WriteLine("Loop Ended");
            Console.WriteLine("Loop Exceution Time in MS :" + stopwatch.ElapsedMilliseconds);

            Console.ReadKey();
        }
    }
}

Output:

concatenation using string builder

As you can see in the above output, it only took 1 millisecond to concatenate the string comparing to 5473 using string. This is because, every time the for loop runs it will not create fresh objects rather than it will use the same memory location.

Why they made C# String as Immutable?

They made Strings as Immutable for Thread Safety. Think one situation where you have many threads and all the threads wants to manipulate the same string object as shown in the below image. If strings are mutable then we have thread safety issues.

Why they made C# String as Immutable?

In case if you are new to thread safety, I strongly recommended you to read the following article, where we discussed Thread and Thread Safety in detail.

https://dotnettutorials.net/lesson/multithreading-in-csharp/

In the next article, I am going to discuss all about Static in C# with examples. Here, in this article, I try to explain Strings in C# with some examples and I hope you enjoy this article. I would like to have your feedback. Please post your feedback, question, or comments about this article.

Leave a Reply

Your email address will not be published. Required fields are marked *