csharp-coding

📁 rcdailey/dotfiles 📅 4 days ago
8
总安装量
8
周安装量
#34198
全站排名
安装命令
npx skills add https://github.com/rcdailey/dotfiles --skill csharp-coding

Agent 安装分布

claude-code 8
mcpjam 7
kilo 7
junie 7
windsurf 7
zencoder 7

Skill 文档

C# Coding Skill

Mandatory patterns and idioms for writing modern C#. All items in this skill are requirements, not suggestions. Use for new code; opportunistically refactor existing code when revisiting.

Framework Detection

Before writing code, check TargetFramework in the project’s csproj to determine the available C# language version. If the csproj has no TargetFramework, look for a Directory.Build.props (or other *.props file) that defines it; these files spread common properties across multiple projects. Only use features whose minimum version tag (e.g., C# 12+) is satisfied by the project. When a mandated feature is unavailable, fall back to the idiomatic alternative for that version.

Required Language Features

  • File-scoped namespaces: namespace MyApp.Core;
  • Primary constructors (C# 12+): class Service(IDep dep, ILogger logger)
  • Collection expressions (C# 12+): [], [item], [..spread]
    • NEVER use new[], new List<T>(), Array.Empty<T>()
    • For type inference, prefer [new T { }, new T { }] over casts
    • Use T[] x = [...] only when simpler forms fail
  • Records for DTOs, init setters
  • Pattern matching: is not null, switch expressions, property patterns
    • Property patterns: obj is Type { Prop: value } over obj is Type t && t.Prop == value
    • Recursive/nested: obj is Type { Outer: { Inner: value } }
    • Extended property pattern: obj is { Outer.Inner: value } (C# 10)
    • Empty property pattern: { } name matches non-null and binds (e.g., is Type { Prop: { } x })
  • Spread operator for collections (C# 12+): [..first, ..second]
  • field keyword in properties (C# 14+): public string Name { get; set => field = value ?? throw; } = "";
    • NEVER use explicit backing fields when field suffices
  • Extension blocks for extension methods and properties (C# 14+): extension(T src) { public bool IsEmpty => !src.Any(); }
    • NEVER use static class with this parameter for new extension methods
  • Null-conditional assignment (C# 14+): obj?.Prop = value; over null checks wrapping assignment
  • Lambda modifiers without types (C# 14+): (text, out result) => int.TryParse(text, out result)
    • NEVER add redundant parameter types when modifiers alone suffice

Required Idioms

Visibility

  • Use internal for implementation classes (CLI apps, service implementations)
  • Use public only for genuine external APIs
  • Concrete classes implementing public interfaces should be internal

Data Modeling

  • Records for data models
  • Favor immutability where reasonable
  • Use immutable collections: IReadOnlyCollection, IReadOnlyDictionary

JSON Serialization

  • Configure naming policy, converters, and style via JsonSerializerOptions (or source-generated JsonSerializerContext) so conventions apply uniformly
  • Check for existing options configuration before creating new instances
  • Reserve per-property attributes ([JsonPropertyName], etc.) for exceptions to the convention

UsedImplicitly Attribute

Mark runtime-used members (deserialization, reflection, DI):

  • [UsedImplicitly] – type instantiated implicitly (DI, empty marker records)
  • [UsedImplicitly(ImplicitUseKindFlags.Assign)] – properties set via deserialization
  • [UsedImplicitly(..., ImplicitUseTargetFlags.WithMembers)] – applies to type AND all members
  • Common for DTOs: [UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.WithMembers)]

Warning Suppression

  • NEVER use #pragma warning disable
  • Use [SuppressMessage] with Justification on class/method level
  • Prefer class-level when multiple members need same suppression

LINQ

  • LINQ method chaining over loops
  • LINQ method syntax only; NEVER use query syntax (from/where/select keywords)

Method Calls

  • Named arguments for boolean literals: new Options(SendInfo: false, SendEmpty: true)
  • Named arguments for consecutive same-type parameters to clarify intent

Async

  • ValueTask for hot paths
  • CancellationToken everywhere (use ct for variable name)

Interfaces

  • Avoid interface pollution: not every service class must have an interface
  • Add interfaces when justified (testability, more than one implementation)

Local Functions

  • Local functions go after return/continue statements
  • Add explicit return; or continue; if needed to separate main logic from local function defs

Design Principles

Quality Gates

  • Zero warnings/analysis issues – treat warnings as errors
  • All code must pass static analysis before commit

Abstraction

  • Prefer polymorphism over enums when modeling behavior or extensibility
  • Propose enum vs polymorphism tradeoffs for discussion rather than defaulting to enums
  • Every abstraction must justify its existence with concrete current needs

Dependency Injection

  • MUST use DI for all dependencies; NEVER manually new service objects in production code
  • Concrete implementations get injected; tests can substitute
  • Search existing registrations before adding new ones

Comment Guidelines

Comments must earn their place by reducing cognitive load. When to comment:

  • LINQ chains (3+ operations): Brief comment stating transformation goal
  • Conditional blocks with non-obvious purpose: One-line comment (e.g., // Explicit: user specified)
  • Private methods: Block comment if name + parameters don’t make purpose self-evident
  • Early returns/continues: Include reason if not obvious from context
  • Complex algorithms: Comment explaining approach at top, not line-by-line
  • Null-suppression operator (!): Every use MUST have an inline comment explaining why null is impossible at that point (e.g., // non-null: validated above, // non-null: dict always contains key after init). The comment documents the runtime guarantee so reviewers can verify it and future maintainers can detect if the invariant breaks.
  • General: Any code where a reader would pause and wonder “why?” or “what’s happening here?”

NEVER:

  • XML doc comments (unless public API library)
  • Commented-out code
  • Restating what code literally does

Tooling

Formatting

  • CSharpier is the ONLY formatting tool
  • NEVER use dotnet format or other formatters
  • Run pre-commit hooks on all changed files

dotnet CLI

  • Use dotnet CLI for: adding/removing packages, adding projects to solution
  • Central package management via Directory.Packages.props – specify versions there, not in csproj
  • Avoid --no-build or --no-restore flags; dotnet test handles restore + build automatically
  • Quiet verbosity for build/test: dotnet build -v q, dotnet test -v q
  • For verbose debugging, pipe to file: dotnet test -v d 2>&1 > /tmp/test.log then search with rg

Project Structure

  • SLNX format preferred over traditional SLN
  • One Autofac/DI module per library to keep registration modular
  • Dotnet tools configured in .config/dotnet-tools.json
  • Keep source files flat in their project directory; create subdirectories only when file count makes navigation difficult