
Modern Csharp Coding Standards
Keep .NET code compile-time safe by banning reflection mappers and applying explicit C# mapping and anti-pattern rules while you build services.
Overview
Modern C# Coding Standards is an agent skill most often used in Build (also Ship review, Operate iterate) that steers solo builders toward explicit, compile-time-checked C# and away from reflection-based mapping anti-pat
Install
npx skills add https://github.com/aaronontheweb/dotnet-skills --skill modern-csharp-coding-standardsWhat is this skill?
- Bans reflection-based object mappers (AutoMapper, Mapster, ExpressMapper) with a documented rationale table
- Promotes explicit extension-method mappings that fail at compile time instead of silent runtime mismatches
- Covers reflection avoidance, UnsafeAccessorAttribute (.NET 8+), and a dedicated anti-patterns section
- Steers solo builders away from metaprogramming magic that breaks in production
- 3 banned reflection mapping libraries listed (AutoMapper, Mapster, ExpressMapper)
- Dedicated sections for reflection avoidance, UnsafeAccessorAttribute (.NET 8+), and anti-patterns
Adoption & trust: 1.4k installs on skills.sh; 989 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You want fast DTO mapping in .NET but reflection libraries hide rename and type mismatches until runtime or production.
Who is it for?
Solo builders on .NET 8+ backends who want predictable mappings and grep-friendly transformation code.
Skip if: Teams committed to AutoMapper/Mapster with heavy custom profiles, or non-.NET stacks where these rules do not apply.
When should I use this skill?
When generating or reviewing C# that might use object mappers, reflection, or common .NET anti-patterns.
What do I get? / Deliverables
Your agent writes explicit mappings and avoids banned mapper libraries so shape errors surface at compile time during implementation and review.
- C# code and mappings that follow explicit, compile-time-checked patterns
- Review comments that cite banned libraries and preferred alternatives
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Canonical shelf is Build because the skill governs how C# is written during implementation of backends and APIs. Backend is the primary fit for C# entity/DTO mapping, records, and service-layer conventions emphasized in the guidelines.
Where it fits
Scaffold UserEntity-to-UserDto mapping with records and extension methods instead of a mapper profile.
Flag a PR that introduced Mapster and suggest explicit mapping aligned with the banned-library table.
Refactor a hot path that used reflection to use statically typed accessors after an incident.
How it compares
Opinionated procedural standards for hand-written C#, not a Roslyn analyzer package or NuGet linter.
Common Questions / FAQ
Who is modern-csharp-coding-standards for?
Indie and solo developers building .NET APIs, services, or CLIs who want the coding agent to follow explicit C# conventions instead of defaulting to reflection mappers.
When should I use modern-csharp-coding-standards?
During Build when scaffolding entities and DTOs, during Ship code review before merge, and during Operate when refactoring legacy mapping code that silently nulls fields.
Is modern-csharp-coding-standards safe to install?
It is documentation-style guidance only; review the Security Audits panel on this Prism page before trusting any third-party skill in your repo.
SKILL.md
READMESKILL.md - Modern Csharp Coding Standards
# Anti-Patterns and Reflection Avoidance Guidelines on avoiding reflection-based metaprogramming and common C# anti-patterns. ## Contents - [Avoid Reflection-Based Metaprogramming](#avoid-reflection-based-metaprogramming) - [UnsafeAccessorAttribute (.NET 8+)](#unsafeaccessorattribute-net-8) - [Anti-Patterns to Avoid](#anti-patterns-to-avoid) ## Avoid Reflection-Based Metaprogramming **Prefer statically-typed, explicit code over reflection-based "magic" libraries.** Reflection-based libraries like AutoMapper trade compile-time safety for convenience. When mappings break, you find out at runtime (or worse, in production) instead of at compile time. ### Banned Libraries | Library | Problem | |---------|---------| | **AutoMapper** | Reflection magic, hidden mappings, runtime failures, hard to debug | | **Mapster** | Same issues as AutoMapper | | **ExpressMapper** | Same issues | ### Why Reflection Mapping Fails ```csharp // With AutoMapper - compiles fine, fails at runtime public record UserDto(string Id, string Name, string Email); public record UserEntity(Guid Id, string FullName, string EmailAddress); // This mapping silently produces garbage: // - Id: string vs Guid mismatch // - Name vs FullName: no match, null/default // - Email vs EmailAddress: no match, null/default var dto = _mapper.Map<UserDto>(entity); // Compiles! Breaks at runtime. ``` ### Use Explicit Mapping Methods Instead ```csharp // Extension method - compile-time checked, easy to find, easy to debug public static class UserMappings { public static UserDto ToDto(this UserEntity entity) => new( Id: entity.Id.ToString(), Name: entity.FullName, Email: entity.EmailAddress); public static UserEntity ToEntity(this CreateUserRequest request) => new( Id: Guid.NewGuid(), FullName: request.Name, EmailAddress: request.Email); } // Usage - explicit and traceable var dto = entity.ToDto(); var entity = request.ToEntity(); ``` ### Benefits of Explicit Mappings | Aspect | AutoMapper | Explicit Methods | |--------|------------|------------------| | **Compile-time safety** | No - runtime errors | Yes - compiler catches mismatches | | **Discoverability** | Hidden in profiles | "Go to Definition" works | | **Debugging** | Black box | Step through code | | **Refactoring** | Rename breaks silently | IDE renames correctly | | **Performance** | Reflection overhead | Direct property access | | **Testing** | Need integration tests | Simple unit tests | ### Complex Mappings For complex transformations, explicit code is even more valuable: ```csharp public static OrderSummaryDto ToSummary(this Order order) => new( OrderId: order.Id.Value.ToString(), CustomerName: order.Customer.FullName, ItemCount: order.Items.Count, Total: order.Items.Sum(i => i.Quantity * i.UnitPrice), Status: order.Status switch { OrderStatus.Pending => "Awaiting Payment", OrderStatus.Paid => "Processing", OrderStatus.Shipped => "On the Way", OrderStatus.Delivered => "Completed", _ => "Unknown" }, FormattedDate: order.CreatedAt.ToString("MMMM d, yyyy")); ``` This is: - **Readable**: Anyone can understand the transformation - **Debuggable**: Set a breakpoint, inspect values - **Testable**: Pass an Order, assert on the result - **Refactorable**: Change a property name, compiler tells you everywhere it's used ### When Reflection is Acceptable Reflection has legitimate uses, but mapping DTOs isn't one of them: | Use Case | Acceptable? | |----------|-------------| | Serialization (System.Text.Json, Newtonsoft) | Yes - well-tested, source generators available | | Dependency injection container | Yes - framework infrastructure | | ORM entity mapping (EF Core) | Yes - necessary for database abstraction | | Test fixtures and builders | Sometimes - for convenience in tests only | | **DTO/domain object mapping** | **No - use explicit methods** | ## UnsafeAccessorAttribute (.NET 8