C# has evolved at a blistering pace over the past few years with .NET 8, 9, and C# 12+. Whether you are preparing for technical interviews or architecting production systems, mastering these core C# pillars is indispensable.
1. Async / Await & Task Cancellation
Asynchronous code in C# frees the thread pool thread while waiting for I/O operations (database queries, HTTP calls, disk reads). Always pass a CancellationToken so long-running requests can be cancelled cleanly if the client disconnects.
public async Task<UserDto> FetchUserAsync(int userId, CancellationToken ct)
{
using var response = await _httpClient.GetAsync($"https://api.example.com/users/{userId}", ct);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<UserDto>(cancellationToken: ct)
?? throw new InvalidOperationException("Failed to deserialize user.");
}
2. Expressive Pattern Matching
Pattern matching eliminates verbose if/else chains and switch statements, making state transitions and object inspection clean and type-safe.
public decimal CalculateDiscount(Customer customer, decimal total) => (customer, total) switch
{
{ customer: { IsVip: true }, total: > 500m } => total * 0.20m, // 20% for big VIP spenders
{ customer: { IsVip: true } } => total * 0.10m, // 10% standard VIP
{ total: > 1000m } => total * 0.05m, // 5% large orders
_ => 0m // No discount
};
3. Records, Primary Constructors & Immutability
C# record types give you immutable reference types with built-in value equality, non-destructive mutation with with expressions, and concise primary constructor syntax.
public record Order(Guid Id, string CustomerEmail, decimal Amount, string Status);
var order1 = new Order(Guid.NewGuid(), "dev@thecodeworld.info", 99.99m, "Pending");
// Immutably create an updated copy with modified status:
var shippedOrder = order1 with { Status = "Shipped" };
4. LINQ & Deferred Execution
LINQ queries are lazily evaluated. They do not execute against the collection or database until an iterating method like .ToList(), .Count(), or a foreach loop runs.
.Count() followed by .FirstOrDefault() on an IEnumerable can re-run queries twice. Materialize with .ToList() or .ToArray() first if reused.