coding-style

A set of rules for writing readable, maintainable C# code with simple abstractions and limited coupling. C# is the programming language commonly used for .NET applications.

In plain words
What is it for?
Use it when designing C# types, choosing records or value objects, deciding whether classes should allow inheritance, and keeping application components focused.
Why use it?
It gives developers consistent choices for data types, classes, dependencies, and functional patterns. This can make code easier to understand and change.

Cursor rule

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add rules/aaronontheweb/dotnet-cursor-rules/coding-style
Clone the repo
git clone --depth 1 https://github.com/Aaronontheweb/dotnet-cursor-rules
Per session 0 Nothing until a file matches its globs; then the whole rule loads.
When invoked 4,602 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00000 $0.04602
Opus 5 $0.00000 $0.02301
Sonnet 5 $0.00000 $0.00920
Haiku 4.5 $0.00000 $0.00460

Measured 2d ago against content hash 0d565248c686, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

coding-style scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

csharp/coding-style.mdc · 748 lines

How it starts

The opening of the file, as written. The whole thing — 748 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Role Definition:

  • C# Language Expert
  • Software Architect
  • Code Quality Specialist

General: Description: > C# code should be written to maximize readability, maintainability, and correctness while minimizing complexity and coupling. Prefer functional patterns and immutable data where appropriate, and keep abstractions simple and focused. Requirements: - Write clear, self-documenting code - Keep abstractions simple and focused - Minimize dependencies and coupling - Use modern C# features appropriately

Type Definitions:

  • Prefer records for data types:
    // Good: Immutable data type with value semantics
    public sealed record CustomerDto(string Name, Email Email);
    
    // Avoid: Class with mutable properties
    public class Customer
    {
        public string Name { get; set; }
        public string Email { get; set; }
    }
    
  • Make classes sealed by default:
    // Good: Sealed by default
    public sealed class OrderProcessor
    {
        // Implementation
    }
    
    // Only unsealed when inheritance is specifically designed for
    public abstract class Repository<T>
    {
        // Base implementation
    }
    
  • Use value objects to avoid primitive obsession:
    // Good: Strong typing with value objects
    public sealed record OrderId(Guid Value)
    {
        public static OrderId New() => new(Guid.NewGuid());
        public static OrderId From(string value) => new(Guid.Parse(value));
    }
    
    // Avoid: Primitive types for identifiers
    public class Order
    {
        public Guid Id { get; set; }  // Primitive obsession
    }
    

Functional Patterns:

  • Use pattern matching effectively:
    // Good: Clear pattern matching
    public decimal CalculateDiscount(Customer customer) =>
        customer switch
        {
            { Tier: CustomerTier.Premium } => 0.2m,
            { OrderCount: > 10 } => 0.1m,
            _ => 0m
        };
    
    // Avoid: Nested if statements
    public decimal CalculateDiscount(Customer customer)
    {
        if (customer.Tier == CustomerTier.Premium)
            return 0.2m;
        if (customer.OrderCount > 10)
            return 0.1m;
        return 0m;
    }
    
  • Prefer pure methods:
    // Good: Pure function
    public static decimal CalculateTotalPrice(
        IEnumerable<OrderLine> lines,
        decimal taxRate) =>
        lines.Sum(line => line.Price * line.Quantity) * (1 + taxRate);
    
    // Avoid: Method with side effects
    public void CalculateAndUpdateTotalPrice()
    {
        this.Total = this.Lines.Sum(l => l.Price * l.Quantity);
        this.UpdateDatabase();
    }
    

Code Organization:

  • Separate state from behavior:
    // Good: Behavior separate from state
    public sealed record Order(OrderId Id, List<OrderLine> Lines);
    
    public static class OrderOperations
    {
        public static decimal CalculateTotal(Order order) =>
            order.Lines.Sum(line => line.Price * line.Quantity);
    }
    
  • Use extension methods appropriately:
    // Good: Extension method for domain-specific operations
    public static class OrderExtensions
    {
        public static bool CanBeFulfilled(this Order order, Inventory inventory) =>
            order.Lines.All(line => inventory.HasStock(line.ProductId, line.Quantity));
    }
    

Dependency Management:

  • Minimize constructor injection:
    // Good: Minimal dependencies
    public sealed class OrderProcessor
    {
        private readonly IOrderRepository _repository;
        
        public OrderProcessor(IOrderRepository repository)
        {
            _repository = repository;
        }
    }
    
    // Avoid: Too many dependencies
    public class OrderProcessor
    {
        public OrderProcessor(
            IOrderRepository repository,
            ILogger logger,
            IEmailService emailService,
            IMetrics metrics,
            IValidator validator)
        {
            // Too many dependencies indicates possible design issues
        }
    }
    
  • Prefer composition with interfaces:
    // Good: Composition with interfaces
    public sealed class EnhancedLogger : ILogger
    {
        private readonly ILogger _baseLogger;
        private readonly IMetrics _metrics;
        
        public EnhancedLogger(ILogger baseLogger, IMetrics metrics)
        {
            _baseLogger = baseLogger;
            _metrics = metrics;
        }
    }
    

Read the full file on GitHub · 748 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 2d ago First seen · 748 lines · 4,602 tokens per session scan A 0d565248c686

Subscribe to this mod's changes

coding-style is a cursor rule published in the GitHub repository Aaronontheweb/dotnet-cursor-rules (134 stars, last pushed 1y ago), licensed Apache-2.0. It costs nothing until one of its globs matches a file; then it loads 4,602 tokens. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.