Improving the performance of C# code

Vaibhav Bhapkar
5 min readMar 13, 2020

--

In this article, we will learn about some of the best practices with C# which we should follow to improve performance of code,

  1. Use String Builder in string concatenation operations:

Strings are a vital part of applications nowadays and building the strings can take a lot of time, along with also causing a performance lag in the applications.

A string is immutable in C# means string cannot be changed once created. For example, the new string “Hello World!!” will occupy a memory space on the heap. Now, by changing the initial string “Hello World!!” to “Hello World Testing !!” will create a new string object on the memory heap instead of modifying the initial string at the same memory address. This behavior will affect the performance if the same string changes multiple times by replacing, appending, removing or inserting new strings in the initial string.

Using String
Using StringBuilder

To overcome this problem, C# introduced the StringBuilder. StringBuilder is a dynamic object that allows you to expand the number of characters in the string. It doesn’t create a new object in the memory but dynamically expands memory to occupy the modified string.

When you analyze the performance of string and StringBuilder. StringBuilder performs shows faster execution time check as shown below,

Program:

using System;using System.Diagnostics;using System.Text;namespace BestPractices{class Program{static void Main(string[] args){string testName = “Vaibhav”;StringBuilder sb = new StringBuilder(“Vaibhav”);// Way 1: Using StringStopwatch st = new Stopwatch();st.Start();for (int i = 0; i < 100; i++){testName = testName + “Test”;}st.Stop();Console.WriteLine(“Using String :-” + st.ElapsedTicks);// Way 2: Using StringBuilderst.Restart();for (int i = 0; i < 100; i++){sb.Append(“Test”);}st.Stop();Console.WriteLine(“Using Stringbuilder :-” + st.ElapsedTicks);Console.ReadLine();}}}

Execution Time Result:

2. Null Checkup:

Whenever you are writing code in C# you will definitely face NullReferenceException in some scenarios Its result of the object which missed for initialization. There are many benefits of having null checkups in your program it helps not only better readability but ensures the program does not terminate due to memory issues.

Example://Without null checkup leads an exceptionstring name = null;Console.WriteLine(name);//With null checkupstring name = null;// Try to enter the value, from somewhereif(name != null) {Console.WriteLine(name);}

3. Asynchronous pattern of programming:

If you are programming using C#, then you are already using async/await keyword to bring responsiveness to your application.

In synchronous programming, if any process is blocked in a synchronous application, the entire application gets blocked and our application stops responding until the whole task completes.

Asynchronous programming is very helpful in this condition. By using Asynchronous programming, the Application can continue with the other work that does not depend on the completion of the whole task. C# will get benefits of asynchronous programming using async and await keyword.

For example:

Consider we have two methods Task1 and Task2 were both of these methods are independent on each other so when you are doing this task in synchronous programming there Task2 will wait till Task1 is going to complete its execution. When we are using asynchronous programming there both od this will run in parallel. Check out below program for this problem,

Program:

using System;using System.Diagnostics;using System.Text;using System.Threading.Tasks;namespace BestPractices{class Program{static void Main(string[] args){_ = Task1();Task2();Console.ReadKey();}public static async Task Task1(){await Task.Run(() =>{for (int i = 0; i < 150; i++){Console.WriteLine(“ From Task 1”);}});}public static void Task2(){for (int i = 0; i < 25; i++){Console.WriteLine(“ From Task 2”);}}}}

Output:

4. Use for loop instead of foreach loop:

for loops are those loops which perform a specific task for ‘n ‘times. In this loop, we can specify iteration value or n value. On the other hand, the foreach loop also works in a similar fashion as for loop works that doing the specific repetitive task but the difference is that here we can not specify iteration value here value automatically decided based on the total collection of an array or ArrayList or object collection.

When you compare the performs for vs foreach loop, for loop perform better than foreach so decide the loop based on your scenario in the project. Check out the example,

Program:

using System;using System.Collections.Generic;using System.Diagnostics;using System.Text;using System.Threading.Tasks;namespace BestPractices{class Program{static void Main(string[] args){List<Int32> totalNumbers = new List<int>();List<Int32> exampleList1 = new List<Int32>();List<Int32> exampleList2 = new List<Int32>();for (int i = 0; i < 10000; i++){totalNumbers.Add(i);}Stopwatch sw = new Stopwatch();sw.Start();for (int i = 0; i < totalNumbers.Count; i++){exampleList1.Add(i);}sw.Stop();Console.Write(“For Loop :- “ + sw.ElapsedTicks + “\n”);sw.Restart();foreach (int a in totalNumbers){exampleList2.Add(a);}sw.Stop();Console.Write(“Foreach Loop:- “ + sw.ElapsedTicks);Console.ReadLine();}}}

Output:

5. Relieve the pressure on the garbage collector:

C# features garbage collection. Garbage collection is the process that determines which object is currently obsolete (not used) and removing them to free some space in memory. But the problem here is the collection process causes the performance penalty so to avoid this better to not collect GC all the time. There are many useful techniques to avoid this one of which I suggest is to do not create object still it really needed and destroy the object whenever you are not using that object.

6. Don’t use empty destructors:

You should not use empty destructors in the program. When you use a destructor, an entry is created in the Finalize queue. Therefore, when the destructor is called, the garbage collector invoked to process the queue. If you have used empty destructor, it causes unnecessary system performance issues. one thing always to remember here is GC execution isn’t cheap in terms of performance.

Note: One thing to note here tips which provided over here not guarantee that your code will perform better because what type/option to choose depends on the use case or problem on which you are working.

Thank You, See you in the next article !!

You can reach out to me here,

LinkedIn: https://www.linkedin.com/in/vaibhav-bhapkar

Email: vaibhavbhapkar.medium@gmail.com

--

--

Vaibhav Bhapkar
Vaibhav Bhapkar

Written by Vaibhav Bhapkar

Technical Speaker | Computer Engineer | Full Stack Web Developer | ML Enthusiast | * Knowledge Shared = Knowledge² *

No responses yet