As a developer, you are always looking for ways to improve the performance of your application.

l will introduce tips for optimizing the performance of your .NET applications, complete with illustrative examples in C#.
 
Now, let's begin !!!
 
  1. Check with NULL value

    Not good:  The == operator can be overridden. So, no guarantee that the results will be as we expect

    var lstEmployee = GetEmployees();

    if (lstEmployee == null)
    {
        // ...
    }

    Good: Using is operator instead

    var lstEmployee = GetEmployees();

    if (lstEmployee is null)
    {
        // ...
    }



  2. Using IDisposable interface to release unmanaged resources

    Not good: unmanaged resources might not be released, causing potential memory leaks
    public class Stock
    {
        private Stream _ioStream;
     
        public Stock(string filePath)
        {
            _ioStream = File.OpenRead(filePath);
        }
     
    }
     
    Good: Release resource after using
    public class Stock: IDisposable
    {
        private Stream _ioStream;
     
        public Stock(string filePath)
        {
            _ioStream = File.OpenRead(filePath);
        }
     
        // Disposing the unmanaged resource.
        public void Dispose()
        {
            _ioStream?.Dispose();
        }
    }


  3. Using ConfigureAwait(false) to prevent deadlocks

    Not good: a risk of potential deadlocks may be occurred
    public async Task<string> LoadData()
    {
        var data = await ReadData();
        return ProcessData(data);
    }
     
    Good: Using ConfigureAwait(false) to avoid potential deadlocks
    public async Task<string> LoadData()
    {
        // Use ConfigureAwait(false) to avoid potential deadlocks
        var data = await ReadData().ConfigureAwait(false);
        return ProcessData(data);
    }


  4. Using Parallel loops to take advantage of multicore CPUs

    Not good: a standard for loop is used to process the data collection, it will execute of sequential operations

    private void ProcessData(List<int> data)
    {
        for (int i = 0; i < data.Count; i++)
        {
            TakeOperation(data[i]);
        }
    }

    Good: Using Parallel loops can speed up processing of large collections, helping to optimize processing times

    private void ProcessData(List<int> data)
    {
        Parallel.ForEach(data, item => TakeOperation(item));
    }



  5. Force immediate execution using ToList() or ToArray() when needed to improve performance


    Not good: IEnumerable will be enumerated multiple times when processing.

    public IEnumerable<int> GetOddNumbers(IEnumerable<int> numbers)
    {
        var odds = numbers.Where(n => n % 2 != 0);

        return odds;
    }

    Good: 

    public IReadOnlyList<int> GetOddNumbers(IEnumerable<int> numbers)
    {
        var odds = numbers.Where(n => n % 2 != 0);

        return odds;
    }



  6. Using StringBuilder instead of concatenate strings in loops

    Not good: a new string object is created when each element of "stringArray" is appended to "result", wasting processing time and memory

    private string ProcessString(string[] stringArray)
    {

        string result = "";
        for (int i = 0; i < stringArray.Count; i++) {
            result += stringArray[i];
        }

        return result;
    }

    Good: use only one StringBuilder, save processing time and memory

    private string ProcessString(string[] stringArray)
    {

        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < stringArray.Count; i++){

          stringBuilder.Append(stringArray[i]);

        }

        return stringBuilder.ToString();
    }



  7. Using Span over arrays to circumvent unnecessary memory allocations and copying

    Not good: Using the arrays may lead to unnecessary memory allocations and copying
    byte[] inputData = GetData();
    ProcessingData(inputData);

    Good: Using Span<T> helps avoid additional memory allocation and copying
    byte[] inputData = GetData();
    Span<byte> spanData = inputData.AsSpan();
    ProcessingData(dataSpan);


  8. Using Lazy Loading for Resources

    Not good: Loading image resource when not needed
    var employeeImage = LoadImage();
    // Some processsing

    Good: Loading image resource when need to use
    Lazy<Bitmap> employeeImage = new Lazy<Bitmap>(() => LoadImage());
    // After doing some processsing
    //...
    // Load the image when accessed
    Bitmap actualEmployeeImage = employeeImage.Value;


    Conclusion:

    These are just a few examples for improving performance when working with C#.

    I hope you find this article is helpful.

    References:

    https://www.c-sharpcorner.com/UploadFile/dacca2/5-tips-to-improve-performance-of-C-Sharp-code/
    https://dev.to/bytehide/7-simple-optimization-tips-in-c-nhn
    https://code-maze.com/csharp-tips-improve-quality-performance/
    https://www.bytehide.com/blog/performance-optimization-tips-csharp
    Image source: https://www.freepik.com/free-vector/stream-binary-code-design_16399103.htm

     

Leave a comment

*