Skip to content

/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

shell
$ npx -y skills add linuxchata/ai-playbook --skill csharp-coding-standards --agent claude-code

How 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
How auto-invocation works

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.md
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,
Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withai-playbook

Rules, skills, and guidelines for AI coding assistants – Claude, Cursor, and beyond.

Get the whole plugin, auto-invoked
Stats
6
Stars
0
Views
0
Forks
Maintained
Maintenance
PowerShell
Language
MIT
License
2mo ago
Last commit
3mo ago
Created

Repo: linuxchata/ai-playbook