C# Performance Best Practices

Optimize your C# applications by following these performance best practices.

Use StringBuilder for String Concatenation
Important
When concatenating multiple strings, especially in loops, use StringBuilder for better performance.

Recommended Approach

// Good
var sb = new StringBuilder();
foreach (var item in items)
{
    sb.AppendLine($"Item: {item.Name}");
}
string result = sb.ToString();

Avoid This Approach

// Bad
string result = "";
foreach (var item in items)
{
    result += $"Item: {item.Name}\n";
}
Prefer Async/Await for I/O Operations
Critical
Use asynchronous programming for I/O bound operations to improve scalability.

Recommended Approach

// Good
public async Task<string> GetDataAsync()
{
    using var client = new HttpClient();
    return await client.GetStringAsync("https://api.example.com/data");
}

Avoid This Approach

// Bad
public string GetData()
{
    using var client = new HttpClient();
    return client.GetStringAsync("https://api.example.com/data").Result;
}
Optimize LINQ Queries
Important
Use efficient LINQ queries to minimize performance overhead and improve execution speed.

Recommended Approach

// Good
var result = data.Where(x => x.IsActive).Select(x => x.Name).ToList();
// Use method syntax for better performance
var result = (from x in data
              where x.IsActive
              select x.Name).ToList();

Avoid This Approach

// Bad
var result = data.Select(x => x.Name).Where(x => x.IsActive).ToList();
Leverage Parallel Processing
Critical
Utilize parallel processing to perform tasks concurrently and improve application throughput.

Recommended Approach

// Good
Parallel.ForEach(data, item =>
{
    ProcessItem(item);
});

Avoid This Approach

// Bad
foreach (var item in data)
{
    ProcessItem(item);  // Sequential processing
}
Optimize Data Structures
Important
Choose the right data structures for your needs to improve performance and memory usage.

Recommended Approach

// Good
List<int> numbers = new List<int>();
for (int i = 0; i < 1000; i++)
{
    numbers.Add(i);
}

Avoid This Approach

// Bad
ArrayList numbers = new ArrayList();
for (int i = 0; i < 1000; i++)
{
    numbers.Add(i);
}
Minimize Boxing and Unboxing
Important
Avoid unnecessary boxing and unboxing to reduce overhead and improve performance.

Recommended Approach

// Good
int number = 123;
object obj = number;  // Boxing
int unboxedNumber = (int)obj;  // Unboxing
// Better
int number = 123;
int sameNumber = number;

Avoid This Approach

// Bad
int number = 123;
object obj = number;  // Boxing
int unboxedNumber = (int)obj;  // Unboxing
Use Caching Strategically
Critical
Implement caching to store frequently accessed data and reduce computation time.

Recommended Approach

// Good
public class DataService
{
    private readonly IMemoryCache _cache;

    public DataService(IMemoryCache cache)
    {
        _cache = cache;
    }

    public string GetData(string key)
    {
        if (!_cache.TryGetValue(key, out string data))
        {
            data = FetchDataFromSource(key);
            _cache.Set(key, data);
        }
        return data;
    }
}

Avoid This Approach

// Bad
public class DataService
{
    public string GetData(string key)
    {
        return FetchDataFromSource(key);  // No caching
    }
}
Avoid Unnecessary Object Creation
Important
Reuse objects instead of creating new ones to reduce memory usage and improve performance.

Recommended Approach

// Good
public class ConnectionManager
{
    private readonly SqlConnection _connection = new SqlConnection();

    public SqlConnection GetConnection()
    {
        return _connection;
    }
}

Avoid This Approach

// Bad
public class ConnectionManager
{
    public SqlConnection GetConnection()
    {
        return new SqlConnection();  // Creates a new connection every time
    }
}