C# Application Performance Optimization: A Beginner's Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Performance Matters from the First Lines of Code



Every developer, even a beginner, encounters situations where a simple application starts to slow down, consume too much memory, or take a long time to process requests. Optimizing the performance of C# applications is not magic or the sole domain of senior developers. It is a set of practical rules and tools that can be mastered at any stage of learning.



In this article, we will break down the key aspects of optimizing C# (.NET) code. You will learn how to avoid common beginner mistakes, speed up work with memory, strings, and collections, and correctly use multithreading. The material is intended for developers who are already familiar with the basics of C# syntax and want to write more efficient code.



1. Working with Strings: Why String is Bad and StringBuilder is Good



One of the most common performance problems in C# is incorrect string handling. Strings in .NET are immutable. This means that any concatenation operation creates a new string object in memory, leaving the old object for the garbage collector.



The Problem: Concatenation in a Loop



Consider a bad example:



string result = "";for (int i = 0; i < 1000; i++){    result += i.ToString() + " ";}// This creates 1000 intermediate strings!


Each loop iteration creates a new string. For 1000 iterations, that's 1000 memory allocations. If there are 100,000 iterations, the application may freeze or throw an OutOfMemoryException.



The Solution: Use StringBuilder



The StringBuilder class works with a mutable character buffer. It does not create new objects each time text is added.



using System.Text;

StringBuilder sb = new StringBuilder();for (int i = 0; i < 1000; i++){ sb.Append(i); sb.Append(" ");}string result = sb.ToString();


Tip: Always use StringBuilder if you are performing more than 3-5 concatenation operations, especially inside loops. For simple concatenation of a few strings (e.g., string s = a + b + c;), the C# compiler optimizes this into a single string.Concat call, so StringBuilder is not needed here.



2. Optimizing LINQ: Choosing the Right Methods



LINQ (Language Integrated Query) is a powerful tool, but its incorrect use can significantly slow down an application. The main problem is multiple enumeration of collections.



Example of an "Expensive" LINQ Query



var numbers = Enumerable.Range(1, 1000000);var countEven = numbers.Where(n => n % 2 == 0).Count();// Here Where() creates an iterator, Count() iterates over it.// This is fine if the collection is enumerated once.


An error occurs when you call multiple terminal operations (Count, ToList, First, Any) on the same LINQ expression:



var query = numbers.Where(n => n % 2 == 0);int count1 = query.Count(); // First passint count2 = query.Count(); // Second pass!// The collection is enumerated twice.


Each call to Count() or ToList() re-executes the filtering. If you have complex filtering or the data source is a database (Entity Framework), this leads to double queries.



The Correct Approach: Materialization



If you need to use the query result multiple times, save it to a list or array:



var query = numbers.Where(n => n % 2 == 0).ToList(); // One passint count1 = query.Count;int count2 = query.Count;


Tip: Use .ToList() or .ToArray() immediately after filtering if you plan to call multiple methods (Count, First, Sum). For a single call, leave

Blogs

Book Recommendations