High-quality C# code should be readable, maintainable, and fast enough for real production traffic.
Use async I/O for scalability
Use async and await for database calls, HTTP requests, and file operations. This reduces blocked threads and improves throughput under load.
public async Task<UserDto?> GetUserAsync(Guid id, CancellationToken ct)
{
var user = await _db.Users
.AsNoTracking()
.FirstOrDefaultAsync(x => x.Id == id, ct);
return user is null ? null : new UserDto(user.Id, user.Email);
}
Avoid unnecessary allocations
Frequent allocations increase GC pressure. Reuse objects when it makes sense, and avoid extra conversions in hot paths.
Tips:
- Prefer
StringBuilderfor repeated string concatenation in loops. - Use
ArrayPool<T>in high-throughput scenarios. - Return lightweight DTOs instead of entire entity graphs.
Optimize LINQ in critical paths
LINQ improves readability, but chained operations can become expensive on large collections.
- Filter early with
Where. - Project only required fields with
Select. - Materialize intentionally (
ToList,ToArray) only when needed.
Query the database efficiently
For EF Core workloads:
- Add indexes for frequent filters and joins.
- Use
AsNoTrackingfor read-only queries. - Prevent N+1 queries by loading related data deliberately.
Measure before and after
Do not optimize blindly. Use profiling and benchmarks to find real bottlenecks.
- Benchmark business-critical methods with BenchmarkDotNet.
- Track latency and allocation metrics in production monitoring.
Strong C# engineering combines clean architecture with targeted performance improvements backed by measurement.