Skip to content
Back to skills

Language Csharp

ASecurity

C# and .NET idioms — .NET 8 LTS, C# NRT, records, value semantics, switch expressions, async/await, Task, ValueTask, CancellationToken, ConfigureAwait, IOptions<T>, LINQ, Span<T>, ArrayPool, hot path, allocation profiling, and performance. Auto-load when working with .cs files, .csproj, .sln, Directory.Build.props, or when the user mentions C#, dotnet, .NET 8, C# NRT, NRT, records, value semantics, switch expressions, Task, ValueTask, CancellationToken, ConfigureAwait, LINQ, Span, or hot-path...

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 3, 2026
developmentc#expresstestingapidatabaseperformance

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 3, 2026

npx -y skills add lugassawan/swe-workbench --skill language-csharp --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Language Csharp?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Language Csharp
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/lugassawan-language-csharp/badge)](https://www.skillsdirectory.com/skills/lugassawan-language-csharp)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: language-csharp
description: C# and .NET idioms — .NET 8 LTS, C# NRT, records, value semantics, switch expressions, async/await, Task, ValueTask, CancellationToken, ConfigureAwait, IOptions<T>, LINQ, Span<T>, ArrayPool, hot path, allocation profiling, and performance. Auto-load when working with .cs files, .csproj, .sln, Directory.Build.props, or when the user mentions C#, dotnet, .NET 8, C# NRT, NRT, records, value semantics, switch expressions, Task, ValueTask, CancellationToken, ConfigureAwait, LINQ, Span, or hot-path code.
---

# C# / .NET

## .NET 8 project shape
- Prefer SDK-style projects with explicit `TargetFramework` (`net8.0`) and shared defaults in `Directory.Build.props`.
- Keep nullable reference types enabled for new code: `<Nullable>enable</Nullable>`.
- Use `ImplicitUsings` when the repository already does; avoid hand-maintaining noisy common imports.
- Keep application, domain, infrastructure, and test projects separate when boundaries are real, not just for ceremony.

```xml
<PropertyGroup>
  <TargetFramework>net8.0</TargetFramework>
  <Nullable>enable</Nullable>
  <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
```

## Nullable reference types
- Treat warnings as design feedback, not noise. Model absence with `T?`, `required`, or a domain type.
- Validate nullable inputs at boundaries; keep internals non-null where possible.
- Use `ArgumentNullException.ThrowIfNull(value)` for guard clauses.
- Avoid `!` except when bridging a framework or serializer limitation; leave a short reason.

```csharp
public sealed class User
{
    public required string Email { get; init; }
    public string? DisplayName { get; init; }
}
```

## Records and value semantics
- Use `record` or `readonly record struct` for immutable value-like data.
- Use classes for identity, lifecycle, mutation, or behavior-heavy objects.
- Be deliberate with `with`: it is copy-with-change, not validation unless constructors enforce invariants.

```csharp
public sealed record Money(decimal Amount, string Currency);

var discounted = price with { Amount = price.Amount * 0.9m };
```

## Pattern matching
- Use patterns for shape-based branching, parsing, and closed domain states.
- Prefer switch expressions when every case returns a value.
- Keep guards (`when`) simple; complex decisions deserve named methods.

```csharp
return command switch
{
    CreateUser(var email) when email.Contains('@') => Create(email),
    DeleteUser(var id) => Delete(id),
    _ => throw new InvalidOperationException("unsupported command")
};
```

## Async and cancellation
- Use `async`/`await` all the way. Avoid `.Result`, `.Wait()`, and blocking over async work.
- Accept and pass `CancellationToken` through I/O, database, and long-running operations.
- In libraries, use `ConfigureAwait(false)` when code does not need a captured context; in modern app code, follow the repo's convention.
- Prefer `Task.WhenAll` for independent work; avoid unobserved fire-and-forget tasks.

```csharp
public async Task<User> GetUserAsync(string id, CancellationToken cancellationToken)
{
    ArgumentException.ThrowIfNullOrWhiteSpace(id);
    return await repository.FindAsync(id, cancellationToken).ConfigureAwait(false)
        ?? throw new UserNotFoundException(id);
}
```

## Dependency injection and options
- Depend on abstractions at boundaries, but do not create interfaces for every class by habit.
- Use constructor injection for required collaborators; avoid service locator patterns.
- Bind configuration to option records and consume `IOptions<T>`, `IOptionsSnapshot<T>`, or `IOptionsMonitor<T>` based on lifetime needs.
- Validate options at startup when invalid configuration should fail fast.

```csharp
public sealed record RetryOptions
{
    public int MaxAttempts { get; init; } = 3;
}

public sealed class Worker(IOptions<RetryOptions> options)
{
    private readonly RetryOptions retry = options.Value;
}
```

## LINQ and performance
- Use LINQ for clear transformations, filtering, grouping, and projections.
- Prefer `Any()` over `Count() > 0`, and avoid repeated enumeration of deferred queries.
- In hot paths, benchmark before replacing readable LINQ with loops.
- Use `Span<T>`, pooling, and allocation-aware APIs only when profiling shows they matter.

```csharp
var activeEmails = users
    .Where(user => user.IsActive)
    .Select(user => user.Email)
    .ToArray();
```

## Doc comments
- **XML doc** — `/// <summary>` one concise sentence; add `<param>`/`<returns>` only when they carry information the signature doesn't (units, valid ranges, ownership).

```csharp
/// <summary>Returns the user's active orders, most recent first.</summary>
public IReadOnlyList<Order> ActiveOrders(string userId) { ... }
```

## Tooling
- **Imports/Format:** `dotnet format`
- **Lint:** Roslyn analyzers (`<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>` in csproj); `dotnet format --verify-no-changes` as formatting gate in CI
- **Test:** `dotnet test` (see Testing below)

## Testing
- xUnit, NUnit, and MSTest are all fine; follow the repository's existing framework.
- Use fluent assertions when already present, and keep tests behavior-focused.
- Mock external boundaries, not records, value objects, or simple domain behavior.

## Avoid
- Disabling nullable warnings instead of fixing the contract.
- Blocking on tasks with `.Result`, `.Wait()`, or `GetAwaiter().GetResult()`.
- Treating dependency injection as a reason to hide every constructor behind an interface.
- Rewriting clear LINQ into loops without a measured performance reason.
- Making ASP.NET conventions the default for non-web .NET code.

Files in this skill

  • SKILL.md5.5 KB
  • triggers.txt373 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…