/csharp-coding-standards
Defines the C# coding standards, patterns, and conventions to be applied consistently across all C# projects. Rules cover naming, structure, async patterns, null handling, dependency injection, logging, result patterns, and formatting. Apply these rules uniformly in all
$ npx -y skills add linuxchata/ai-playbook --skill csharp-coding-standards --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/csharp-coding-standards
Context preview
The summary Claude sees to decide when to auto-load this skill.
Defines the C# coding standards, patterns, and conventions to be applied consistently across all C# projects. Rules cover naming, structure, async patterns, null handling, dependency injection, logging, result patterns, and formatting. Apply these rules uniformly in all
SKILL.md
csharp-coding-standards.SKILL.mdname: csharp-coding-standards
description: Defines the C# coding standards, patterns, and conventions to be applied consistently across all C# projects. Rules cover naming, structure, async patterns, null handling, dependency injection, logging, result patterns, and formatting. Apply these rules uniformly in all production code.
metadata:
version: 1.1.0
C# Coding Standards
Description
Defines the C# coding standards, patterns, and conventions to be applied consistently across all C# projects. Rules cover naming, structure, async patterns, null handling, dependency injection, logging, result patterns, and formatting. Apply these rules uniformly in all production code.
---
1. File & Namespace Structure
1.1 File-Scoped Namespaces
Always use **file-scoped namespaces**:
// ✅ Correct
namespace MyApp.Core.Validators;
internal class OrderValidator { }
// ❌ Wrong
namespace MyApp.Core.Validators
{
internal class OrderValidator { }
}1.2 Using Directives
- Place `using` directives **outside** the namespace.
- Group: System namespaces first, then others ordered alphabetically – separated by a blank line.
- Use implicit usings where available; add explicit usings only when needed for disambiguation.
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using MyApp.Core.Abstractions;
using MyApp.Domain;
1.3 One Type Per File
Each file contains exactly one top-level type. The file name must match the type name exactly.
---
2. Naming Conventions
2.1 Types
| Kind | Convention | Example | |---|---|---| | Classes | PascalCase | `OrderValidator`, `UserService` | | Interfaces | `I` prefix + PascalCase | `IOrderRepository`, `IUserService` | | Enums | PascalCase | `OrderStatus`, `PaymentMethod` | | Structs | PascalCase | `Money`, `DateRange` | | Records | PascalCase | `AppConfiguration`, `UserSettings` |
2.2 Members
| Kind | Convention | Example | |---|---|---| | Public properties | PascalCase | `CreatedAt`, `TotalAmount` | | Public methods | PascalCase | `CreateOrder`, `ValidatePayment` | | Private fields | `_camelCase` (underscore prefix) | `_repository`, `_logger` | | Constants | PascalCase | `DefaultTimeout`, `MaxRetryCount` | | Local variables | camelCase | `orderId`, `serializedData` | | Method parameters | camelCase | `cancellationToken`, `userId` | | Lambda parameters | Short camelCase | `x =>`, `e =>`, `o =>` |
2.3 Async Methods
> **All async methods MUST end with the `Async` suffix without exception.**
// ✅ Correct
public async Task<Order?> GetByIdAsync(Guid id, CancellationToken cancellationToken);
// ❌ Wrong – missing Async suffix
public async Task<Order?> GetById(Guid id, CancellationToken cancellationToken);
This applies to:
- Interface declarations
- Public and internal implementation methods
- Private helper methods
---
3. Access Modifiers & Sealed Classes
3.1 Least Privilege
- Prefer `internal` for implementation types; use `public` only for types that are part of the public API surface.
- Implementation classes registered via DI should be `internal sealed`.
- Types that implement a public interface and form the public API are `public sealed`.
// ✅ Correct: public sealed for types exposed via public interface
public sealed class OrderService : IOrderService { }
// ✅ Correct: internal sealed for infrastructure implementations
internal sealed class SqlOrderRepository : IOrderRepository { }3.2 `sealed` Usage
Mark classes `sealed` by default unless inheritance is explicitly required. This prevents unintended derivation and enables JIT optimizations.
---
4. Null Handling & Defensive Programming
4.1 Nullable Reference Types
- Enable nullable context for all projects (`<Nullable>enable</Nullable>`).
- Annotate all nullable references explicitly with `?`.
- Avoid the null-forgiving operator (`!`) without an inline comment explaining why it is safe.
- Prefer early-return guards over deeply nested null checks.
// ✅ Early return guard
if (id is null || id.Length == 0)
{
return null;
}4.2 Argument Validation
Use modern `ArgumentNullException` helpers for public/internal method boundaries:
// ✅ Correct
ArgumentNullException.ThrowIfNull(order);
ArgumentNullException.ThrowIfNullOrEmpty(order.UserName);
4.3 Null Propagation & Coalescing
Prefer `?.` and `??` / `??=` over verbose null checks in expressions:
// ✅ Correct
return items?.Select(x => x.ToDto()).ToArray();
var name = input?.Trim() ?? string.Empty;
---
5. Constructor Injection & Dependency Injection
5.1 Constructor Injection
Always inject dependencies via the constructor. Store them as `private readonly` fields prefixed with `_`.
private readonly IOrderRepository _orderRepository;
private readonly ILogger<OrderService> _logger;
public OrderService(IOrderRepository orderRepository, ILogger<OrderService> logger)
{
_orderRepository = orderRepository;
_logger = logger;
}5.2 Options Pattern
Access configuration via `IOptions<T>`. Extract `.Value` in the constructor and store as a field – do not access `.Value` repeatedly at call sites.
private readonly AppConfiguration _configuration;
public OrderService(IOptions<AppConfiguration> options)
{
_configuration = options.Value;
}5.3 DI Registration
Centralize all service registrations in a dedicated `DependencyInjection.cs` static class with `IServiceCollection` extension methods.
public static class DependencyInjection
{
public static void AddMyFeature(this IServiceCollection services, IConfiguration configuration)
{
services.AddTransient<IOrderService, OrderService>();
services.AddKeyedTransient<IPaymentStrategy, CreditCardStrategy>("creditcard");
}
}Lifetime guidance:
- `AddTransient` – stateless, short-lived services.
- `AddSingleton` – thread-safe,
Read more
name: csharp-coding-standards description: Defines the C# coding standards, patterns, and conventions to be applied consistently across all C# projects. Rules cover naming, structure, async patterns, null handling, dependency injection, logging, result patterns, and formatting. Apply these rules uniformly in all production code. metadata: version: 1.1.0
C# Coding Standards
Description
Defines the C# coding standards, patterns, and conventions to be applied consistently across all C# projects. Rules cover naming, structure, async patterns, null handling, dependency injection, logging, result patterns, and formatting. Apply these rules uniformly in all production code.
---
1. File & Namespace Structure
1.1 File-Scoped Namespaces
Always use **file-scoped namespaces**:
// ✅ Correct
namespace MyApp.Core.Validators;
internal class OrderValidator { }
// ❌ Wrong
namespace MyApp.Core.Validators
{
internal class OrderValidator { }
}1.2 Using Directives
- Place `using` directives **outside** the namespace.
- Group: System namespaces first, then others ordered alphabetically – separated by a blank line.
- Use implicit usings where available; add explicit usings only when needed for disambiguation.
using System.Text; using System.Text.Json; using Microsoft.Extensions.Logging; using MyApp.Core.Abstractions; using MyApp.Domain;
1.3 One Type Per File
Each file contains exactly one top-level type. The file name must match the type name exactly.
---
2. Naming Conventions
2.1 Types
| Kind | Convention | Example | |---|---|---| | Classes | PascalCase | `OrderValidator`, `UserService` | | Interfaces | `I` prefix + PascalCase | `IOrderRepository`, `IUserService` | | Enums | PascalCase | `OrderStatus`, `PaymentMethod` | | Structs | PascalCase | `Money`, `DateRange` | | Records | PascalCase | `AppConfiguration`, `UserSettings` |
2.2 Members
| Kind | Convention | Example | |---|---|---| | Public properties | PascalCase | `CreatedAt`, `TotalAmount` | | Public methods | PascalCase | `CreateOrder`, `ValidatePayment` | | Private fields | `_camelCase` (underscore prefix) | `_repository`, `_logger` | | Constants | PascalCase | `DefaultTimeout`, `MaxRetryCount` | | Local variables | camelCase | `orderId`, `serializedData` | | Method parameters | camelCase | `cancellationToken`, `userId` | | Lambda parameters | Short camelCase | `x =>`, `e =>`, `o =>` |
2.3 Async Methods
> **All async methods MUST end with the `Async` suffix without exception.**
// ✅ Correct public async Task<Order?> GetByIdAsync(Guid id, CancellationToken cancellationToken); // ❌ Wrong – missing Async suffix public async Task<Order?> GetById(Guid id, CancellationToken cancellationToken);
This applies to:
- Interface declarations
- Public and internal implementation methods
- Private helper methods
---
3. Access Modifiers & Sealed Classes
3.1 Least Privilege
- Prefer `internal` for implementation types; use `public` only for types that are part of the public API surface.
- Implementation classes registered via DI should be `internal sealed`.
- Types that implement a public interface and form the public API are `public sealed`.
// ✅ Correct: public sealed for types exposed via public interface
public sealed class OrderService : IOrderService { }
// ✅ Correct: internal sealed for infrastructure implementations
internal sealed class SqlOrderRepository : IOrderRepository { }3.2 `sealed` Usage
Mark classes `sealed` by default unless inheritance is explicitly required. This prevents unintended derivation and enables JIT optimizations.
---
4. Null Handling & Defensive Programming
4.1 Nullable Reference Types
- Enable nullable context for all projects (`<Nullable>enable</Nullable>`).
- Annotate all nullable references explicitly with `?`.
- Avoid the null-forgiving operator (`!`) without an inline comment explaining why it is safe.
- Prefer early-return guards over deeply nested null checks.
// ✅ Early return guard
if (id is null || id.Length == 0)
{
return null;
}4.2 Argument Validation
Use modern `ArgumentNullException` helpers for public/internal method boundaries:
// ✅ Correct ArgumentNullException.ThrowIfNull(order); ArgumentNullException.ThrowIfNullOrEmpty(order.UserName);
4.3 Null Propagation & Coalescing
Prefer `?.` and `??` / `??=` over verbose null checks in expressions:
// ✅ Correct return items?.Select(x => x.ToDto()).ToArray(); var name = input?.Trim() ?? string.Empty;
---
5. Constructor Injection & Dependency Injection
5.1 Constructor Injection
Always inject dependencies via the constructor. Store them as `private readonly` fields prefixed with `_`.
private readonly IOrderRepository _orderRepository;
private readonly ILogger<OrderService> _logger;
public OrderService(IOrderRepository orderRepository, ILogger<OrderService> logger)
{
_orderRepository = orderRepository;
_logger = logger;
}5.2 Options Pattern
Access configuration via `IOptions<T>`. Extract `.Value` in the constructor and store as a field – do not access `.Value` repeatedly at call sites.
private readonly AppConfiguration _configuration;
public OrderService(IOptions<AppConfiguration> options)
{
_configuration = options.Value;
}5.3 DI Registration
Centralize all service registrations in a dedicated `DependencyInjection.cs` static class with `IServiceCollection` extension methods.
public static class DependencyInjection
{
public static void AddMyFeature(this IServiceCollection services, IConfiguration configuration)
{
services.AddTransient<IOrderService, OrderService>();
services.AddKeyedTransient<IPaymentStrategy, CreditCardStrategy>("creditcard");
}
}Lifetime guidance:
- `AddTransient` – stateless, short-lived services.
- `AddSingleton` – thread-safe,
Showing the first part of this file.
Rules, skills, and guidelines for AI coding assistants – Claude, Cursor, and beyond.
Repo: linuxchata/ai-playbook
Other skills on ai-playbook.
- /csharp-api-controller-standards
Defines the coding standards, patterns, and conventions for ASP.NET Core REST API controllers. Rules cover routing, HTTP verbs, response types, XML documentation, dependency injection, and asynchronous execution. Apply these rules uniformly to ensure a consistent, predictable,
Open skill - /csharp-testing-standards
Defines the testing standards, patterns, and conventions for all C# unit and integration test projects. Rules cover test framework usage, naming, structure, mocking, assertions, and parameterization. Apply these rules uniformly across all test projects.
Open skill

