type-design-performance

Guides .NET type design decisions covering structs, records, spans, and collection selection for performance.

Updated Mar 8, 2026
One-click install
npx skills add https://github.com/AGIBuild/dotnet.CI.template --skill type-design-performance-agibuild
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: type-design-performance
Source: https://github.com/AGIBuild/dotnet.CI.template/tree/main/.cursor/skills/csharp-type-design-performance
Command: npx skills add https://github.com/AGIBuild/dotnet.CI.template --skill type-design-performance-agibuild

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Choosing between class, struct, and record in .NET has cascading effects on allocation, GC pressure, and API shape, and wrong choices cause hidden costs like defensive copies, boxing, and unnecessary heap allocations. This Skill provides decision matrices and concrete patterns so type design choices are made deliberately instead of by default. ## Core Features & Use Cases - Struct vs Class Decision Matrix: Size, lifetime, identity, and mutability criteria with byte-size thresholds for choosing value vs reference types. - Performance Patterns: Sealed-by-default classes, readonly structs to eliminate defensive copies, static pure functions, deferred enumeration, and ValueTask guidance for hot paths. - Memory and Collection Selection: Span<T> vs Memory<T> rules for sync and async code, FrozenDictionary for read-heavy lookups, and immutable collection return types for public APIs. - Use Case: When reviewing a pull request that introduces a mutable struct or returns List<T> from a public API, apply the checklists and anti-patterns to identify and fix the performance issues. ## Quick Start Review this C# type definition and tell me whether it should be a class, readonly struct, or record based on the decision matrix.

Frequently Asked Questions about type-design-performance

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I choose between struct and class in C#?▼

Choose a struct when the type is small (ideally 16 bytes or fewer, up to 64 bytes), short-lived, immutable, and has value equality semantics. Choose a class for large or variable-size data, long-lived shared instances, reference identity, or when inheritance is required.

When should I use Span<T> vs Memory<T> in .NET?▼

Use Span<T> for synchronous methods and stackalloc buffers since it is a stack-only ref struct with the lowest overhead. Use Memory<T> when the buffer must be used in async methods, stored in fields, or passed to callbacks, converting to Span via .Span for synchronous processing.

What is the difference between record class and record struct?▼

A record class is heap-allocated and supports null for absence, making it suitable for DTOs. A readonly record struct is stack-allocated with value semantics, ideal for small value objects like Money, where default represents an empty state.

When should I use ValueTask instead of Task?▼

Use ValueTask on hot paths that frequently complete synchronously, such as cache hits, to avoid Task allocation. For real I/O operations use Task, and never await a ValueTask more than once or block on it with .Result.

When should I use FrozenDictionary in .NET?▼

Use FrozenDictionary on .NET 8+ for lookup tables built once and read many times, such as configuration mappings or static handler registries, since it optimizes internal layout for read speed. Avoid it for data that changes at runtime or very small lookups.

Why should structs be readonly in C#?▼

Non-readonly structs force the JIT to create defensive copies when methods are called through in parameters or readonly fields, adding hidden cost. Marking a struct readonly guarantees immutability, eliminates those copies, and prevents subtle mutation bugs.