---
name: csharp-developer
description: This skill should be used by AI agents to assist with C# development tasks, including writing, reviewing, and debugging C# code.
---

# C# Developer Skill

## Build, Test, and Development Commands
- `dotnet restore`: restores all solution packages. If you encounter issues after package installation or update, try running `dotnet restore --no-cache` to clear the local cache.
- `dotnet build *.sln`: builds all project in the solution. You can use "TreatWarningsAsErrors" while running build as a good way to make sure there are no warnings in projects. Always perform build after backend changes.
- `dotnet format`: applies code style from `.editorconfig` and analyzers. If this command fails without a clear reason - use `dotnet format --verify-no-changes` that will output errors that couldn't be fixed automatically.

## Coding Style & Naming Conventions
- Language: C# 14 on .NET SDK `10.x` (see `global.json`).
- Style: enforced via `.editorconfig` and analyzers; keep code warning-free (TreatWarningsAsErrors=true during validation).
- Indentation: 4 spaces; use expression-bodied members when clear; prefer `readonly`/`sealed`.
- Implementation: if a public interface is exposed, the implementation class should be `internal sealed`.
- Naming: PascalCase for types/methods, camelCase for locals/parameters, `_camelCase` for private fields; namespaces match folder and project names.
- **GUID Generation**: When creating GUIDs that will be saved to the database, always use `Guid.CreateVersion7()` instead of `Guid.NewGuid()`. UUIDv7 provides better database performance due to sequential ordering.

- Modern C#::
  - Primary constructors: `public sealed class Foo(IBar bar) : IFoo`.
  - Collection initializers: `opt.OAuthScopes([.. settings.Scopes.Keys]);`.
  - Pattern matching: `if (obj is IFoo foo) { /* ... */ }`.
  - Records for immutables: `public record Employee(int Id, string Name);`.
  - Null checks: `if (obj is null)` / `if (obj is not null)`.

## C# Language Features
The framework leverages modern C# features consistently:
- **Primary Constructors**: Use for dependency injection in services and controllers:
  ```csharp
  public sealed class EmployeeContextModule(IEmployeeContextProvider employeeContextProvider, IAuthInfoProvider authInfoProvider) : IBusinessObjectModule
  ```
- **Collection Initializers**: Use for initializing arrays and lists:
  ```csharp
  opt.OAuthScopes([.. swaggerOpenApiOAuthSettings.Scopes.Keys]);
  ```
- **Pattern Matching**: Use for concise type checks and casting:
  ```csharp
  if (obj is IEmployeeContextProvider employeeContextProvider)
  {
      // Use employeeContextProvider
  }
  ```
- **Records**: Use for immutable data structures:
  ```csharp
    public record Employee(int Id, string Name);
  ```
  - For records where all properties are required, use primary constructors instead of property syntax:
    ```csharp
    // Good: Primary constructor for required properties
    public sealed record RunStatistics(
        int TotalRuns,
        int CompletedRuns,
        int FailedRuns);
    
    // Bad: Property syntax for simple required properties
    public sealed record RunStatistics
    {
        public required int TotalRuns { get; init; }
        public required int CompletedRuns { get; init; }
    }
    ```
- **`is` and `is not` operator used for null checks**: 
  ```csharp
  if (obj is not null)
  {
      // Do something with obj
  }
  if (obj is null)
  {
      // Handle null case
  }
  ```
