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
}
}