C# Language Patterns
Priority: P0 (CRITICAL)
Modern C# standards for type-safe, performant, maintainable code.
Implementation Guidelines
- Nullable Reference Types: Enable
<Nullable>enable</Nullable>. Use ? for nullable, avoid ! except when compiler can't infer.
- Records:
record for immutable DTOs, record struct for stack-allocated value types.
- Pattern Matching:
is patterns, switch expressions, property/positional patterns.
- Async/Await: Always use
CancellationToken. ValueTask for hot paths. ConfigureAwait(false) in libraries.
- LINQ: Prefer method syntax. Avoid multiple enumerations (
ToList() once). Use AsNoTracking() for read-only EF queries.
- Generics: Constraints (
where T : class, new()), covariance (out T), contravariance (in T).
- Spans:
Span<T>, ReadOnlySpan<T> for zero-allocation slicing.
- Primary Constructors: C# 12+
class Foo(int x) for concise DI.
- Collection Expressions: C# 12+
[1, 2, 3] syntax.
- Raw String Literals:
"""multi-line""" for SQL, JSON templates.
Anti-Patterns
- No
async void: Use async Task. Exception: event handlers.
- No
Task.Result/.Wait(): Deadlock risk. Always await.
- No
DateTime.Now: Use DateTimeOffset.UtcNow for timezone safety.
- No string concat in loops: Use
StringBuilder or string.Join.
- No
! abuse: Prefer null checks or ?? over null-forgiving.
Code
// Record with primary constructor
public record UserDto(string Name, string Email);
// Pattern matching with switch expression
string GetStatus(Order order) => order switch
{
{ Status: OrderStatus.Pending } => "Waiting",
{ Status: OrderStatus.Shipped, TrackingNumber: not null } => "In Transit",
{ IsCancelled: true } => "Cancelled",
_ => "Unknown"
};
// Async with cancellation token
async Task<User?> GetUserAsync(int id, CancellationToken ct = default)
{
return await _db.Users
.AsNoTracking()
.FirstOrDefaultAsync(u => u.Id == id, ct);
}
// Span for zero-allocation parsing
ReadOnlySpan<char> GetFirstWord(ReadOnlySpan<char> text)
{
int idx = text.IndexOf(' ');
return idx < 0 ? text : text[..idx];
}
// Primary constructor (C# 12)
public class UserService(IUserRepository repo, ILogger<UserService> logger)
{
public async Task<User?> GetAsync(int id) => await repo.GetByIdAsync(id);
}
Reference & Examples
For advanced patterns, spans, and nullable annotations:
See references/REFERENCE.md.
Related Topics
best-practices | security | tooling
1---2name: c-language-patterns3description: Modern C# standards for type safety, performance, and maintainability.4---56# C# Language Patterns78## **Priority: P0 (CRITICAL)**910Modern C# standards for type-safe, performant, maintainable code.1112## Implementation Guidelines1314- **Nullable Reference Types**: Enable `<Nullable>enable</Nullable>`. Use `?` for nullable, avoid `!` except when compiler can't infer.15- **Records**: `record` for immutable DTOs, `record struct` for stack-allocated value types.16- **Pattern Matching**: `is` patterns, `switch` expressions, property/positional patterns.17- **Async/Await**: Always use `CancellationToken`. `ValueTask` for hot paths. `ConfigureAwait(false)` in libraries.18- **LINQ**: Prefer method syntax. Avoid multiple enumerations (`ToList()` once). Use `AsNoTracking()` for read-only EF queries.19- **Generics**: Constraints (`where T : class, new()`), covariance (`out T`), contravariance (`in T`).20- **Spans**: `Span<T>`, `ReadOnlySpan<T>` for zero-allocation slicing.21- **Primary Constructors**: C# 12+ `class Foo(int x)` for concise DI.22- **Collection Expressions**: C# 12+ `[1, 2, 3]` syntax.23- **Raw String Literals**: `"""multi-line"""` for SQL, JSON templates.2425## Anti-Patterns2627- **No `async void`**: Use `async Task`. Exception: event handlers.28- **No `Task.Result`/`.Wait()`**: Deadlock risk. Always `await`.29- **No `DateTime.Now`**: Use `DateTimeOffset.UtcNow` for timezone safety.30- **No string concat in loops**: Use `StringBuilder` or `string.Join`.31- **No `!` abuse**: Prefer null checks or `??` over null-forgiving.3233## Code3435```csharp36// Record with primary constructor37public record UserDto(string Name, string Email);3839// Pattern matching with switch expression40string GetStatus(Order order) => order switch41{42 { Status: OrderStatus.Pending } => "Waiting",43 { Status: OrderStatus.Shipped, TrackingNumber: not null } => "In Transit",44 { IsCancelled: true } => "Cancelled",45 _ => "Unknown"46};4748// Async with cancellation token49async Task<User?> GetUserAsync(int id, CancellationToken ct = default)50{51 return await _db.Users52 .AsNoTracking()53 .FirstOrDefaultAsync(u => u.Id == id, ct);54}5556// Span for zero-allocation parsing57ReadOnlySpan<char> GetFirstWord(ReadOnlySpan<char> text)58{59 int idx = text.IndexOf(' ');60 return idx < 0 ? text : text[..idx];61}6263// Primary constructor (C# 12)64public class UserService(IUserRepository repo, ILogger<UserService> logger)65{66 public async Task<User?> GetAsync(int id) => await repo.GetByIdAsync(id);67}68```6970## Reference & Examples7172For advanced patterns, spans, and nullable annotations:73See [references/REFERENCE.md](references/REFERENCE.md).7475## Related Topics7677best-practices | security | tooling