--- paths: - "**/*.cs" - "**/*.csx" --- # C# Coding Style > This file extends [common/coding-style.md](../common/coding-style.md) with C#-specific content. ## Standards - Follow current .NET conventions and enable nullable reference types - Prefer explicit access modifiers on public and internal APIs - Keep files aligned with the primary type they define ## Types and Models - Prefer `record` or `record struct` for immutable value-like models - Use `class` for entities or types with identity and lifecycle - Use `interface` for service boundaries and abstractions - Avoid `dynamic` in application code; prefer generics or explicit models ```csharp public sealed record UserDto(Guid Id, string Email); public interface IUserRepository { Task FindByIdAsync(Guid id, CancellationToken cancellationToken); } ``` ## Immutability - Prefer `init` setters, constructor parameters, and immutable collections for shared state - Do not mutate input models in-place when producing updated state ```csharp public sealed record UserProfile(string Name, string Email); public static UserProfile Rename(UserProfile profile, string name) => profile with { Name = name }; ``` ## Async and Error Handling - Prefer `async`/`await` over blocking calls like `.Result` or `.Wait()` - Pass `CancellationToken` through public async APIs - Throw specific exceptions and log with structured properties ```csharp public async Task LoadOrderAsync( Guid orderId, CancellationToken cancellationToken) { try { return await repository.FindAsync(orderId, cancellationToken) ?? throw new InvalidOperationException($"Order {orderId} was not found."); } catch (Exception ex) { logger.LogError(ex, "Failed to load order {OrderId}", orderId); throw; } } ``` ## Formatting - Use `dotnet format` for formatting and analyzer fixes - Keep `using` directives organized and remove unused imports - Prefer expression-bodied members only when they stay readable