Claude-skill-registry dotnet8-standards
C# 12 and .NET 8 coding standards including primary constructors, collection expressions, async patterns, null handling, and naming conventions. Use when writing or reviewing .NET 8 code.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dotnet8-standards" ~/.claude/skills/majiayu000-claude-skill-registry-dotnet8-standards && rm -rf "$T"
manifest:
skills/data/dotnet8-standards/SKILL.mdsource content
.NET 8 Coding Standards
Overview
These standards ensure consistent, modern C# code across the codebase. Follow these patterns for all .NET 8 development.
C# 12 Syntax
Primary Constructors
Use primary constructors for dependency injection:
// Good - primary constructor public class TaskService(ITaskRepository repository, ILogger<TaskService> logger) { public async Task<TaskItem> GetByIdAsync(Guid id) => await repository.GetByIdAsync(id); } // Avoid - traditional constructor public class TaskService { private readonly ITaskRepository _repository; public TaskService(ITaskRepository repository) => _repository = repository; }
Collection Expressions
Use collection expressions for initialization:
// Good List<string> items = ["one", "two", "three"]; int[] numbers = [1, 2, 3]; // Avoid var items = new List<string> { "one", "two", "three" };
Naming Conventions
Classes and Methods
- PascalCase for classes, methods, properties:
,TaskService
,GetAllAsyncIsCompleted - Async methods suffix with
:Async
,GetByIdAsyncCreateAsync
Variables and Parameters
- camelCase for local variables and parameters:
,taskIdpageSize - No Hungarian notation or prefixes
- Descriptive names over abbreviations:
notcancellationTokenct
Interfaces
- Prefix with
:I
,ITaskServiceITaskRepository
Async/Await Patterns
Always Use CancellationToken
// Good - accepts and passes CancellationToken public async Task<List<TaskItem>> GetAllAsync(CancellationToken cancellationToken = default) { return await repository.GetAllAsync(cancellationToken); } // Avoid - no cancellation support public async Task<List<TaskItem>> GetAllAsync() { return await repository.GetAllAsync(); }
ConfigureAwait
In library code, use
ConfigureAwait(false):
await repository.GetAllAsync(cancellationToken).ConfigureAwait(false);
In ASP.NET Core controllers/services, it's optional (HttpContext flows automatically).
Null Handling
Nullable Reference Types
Enable nullable reference types (already in csproj):
// Explicit nullability public string? Description { get; set; } // Can be null public string Title { get; set; } = string.Empty; // Cannot be null
Null Checks
Use pattern matching for null checks:
// Good if (task is null) return NotFound(); if (task is not null) Process(task); // Avoid if (task == null) return NotFound();
Property Initialization
Required Properties
Use
required modifier for mandatory properties:
public class CreateTaskRequest { public required string Title { get; init; } public string? Description { get; init; } }
Init-Only Properties
Use
init for immutable properties:
public class TaskItem { public Guid Id { get; init; } public required string Title { get; init; } public DateTime CreatedAt { get; init; } = DateTime.UtcNow; }
Records for DTOs
Use records for request/response DTOs:
public record CreateTaskRequest(string Title, string? Description); public record TaskResponse(Guid Id, string Title, string? Description, bool IsCompleted);
File-Scoped Namespaces
Always use file-scoped namespaces:
// Good namespace TaskApi.Services; public class TaskService { } // Avoid namespace TaskApi.Services { public class TaskService { } }
Expression-Bodied Members
Use for single-line implementations:
// Good public string FullName => $"{FirstName} {LastName}"; public override string ToString() => Title; // Use block body for multi-line public async Task<TaskItem?> GetByIdAsync(Guid id) { var task = await repository.GetByIdAsync(id); logger.LogInformation("Retrieved task {Id}", id); return task; }