CO

coding-standards

Enforces modern C# 14 and .NET 10 standards for new code generation.

Install

mkdir -p .claude/skills/coding-standards-dotnet && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/10416" && unzip -o skill.zip -d .claude/skills/coding-standards-dotnet && rm skill.zip

Installs to .claude/skills/coding-standards-dotnet

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

C# and .NET coding standards for generating new code files. Use when creating new classes, methods, controls, tests, or any new C# / VB source files in this repository. Covers C# 14 / .NET 10 patterns, naming, formatting, XML docs, WinForms conventions, and performance idioms.
277 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Beginner

Key capabilities

  • Generate new C# classes
  • Generate unit tests
  • Apply C# 14 patterns
  • Manage namespaces and XML docs
  • Implement WinForms conventions

How it works

It enforces specific coding standards, including framework versioning, namespace management, and modern C# pattern usage for new files.

Inputs & outputs

You give it
New code generation request
You get back
C# or VB.NET source file

When to use coding-standards

  • Creating new C# classes
  • Generating unit tests
  • Scaffolding new .NET features

About this skill

Coding Standards — New Code Generation

These rules apply whenever you generate new C# or VB.NET source files in this repository. For modernizing or refactoring existing files, see the code-modernization skill instead.

Target Framework

  • Default target is .NET 10.0 (net10.0).
  • Some files target .NET Framework or are multi-targeted — check the project file before generating.
  • Do not edit files under eng/common/.
  • Follow all rules defined in .editorconfig.

Language Version

Use C# 14 features and patterns. Key features to prefer:

FeatureExample
Extension members (extension blocks)extension(string s) { public bool IsBlank() => ... }
field keyword in propertiesset => field = value ?? throw ...;
Null-conditional assignmentcustomer?.Order = GetOrder();
nameof on unbound genericsnameof(List<>)
Lambda modifiers without types(text, out result) => int.TryParse(text, out result)
Partial constructors / eventspartial MyClass() { }
First-class Span<T> conversionsImplicit T[]Span<T> / ReadOnlySpan<T>

General Assumptions

  • Namespace imports are defined in a global usings file — omit standard using directives unless the import is non-obvious.
  • Nullable Reference Types are enabled — annotate all new code accordingly.
  • Use file-scoped namespace declarations.

Type Usage and var Policy

Apply the following rules in priority order:

  1. Never use var for primitive types. Always spell out int, string, bool, double, float, decimal, char, byte, long, etc.
// REQUIRED — explicit types for primitives
int count = 5;
string name = "Button";
bool isVisible = true;
  1. Use var when the type is already visible or clearly implied on the same line. Repeating the type degrades readability. This applies to:

    • Casts: var foo = (SomeType) bar;
    • as casts: var button = item as ToolStripDropDownButton;
    • Generic methods with explicit type argument(s): Assume the return type matches the generic type parameter — even when the method signature technically returns a base type — because the <T> already tells the reader what they are getting back: var host = this.GetService<IDesignerHost>(); var session = provider.GetRequiredService<DesignerSession>();
    • out var in generic methods that name the type: site.TryGetService<INestedContainer>(out var container) — the <T> already specifies the type.
    • Methods whose name contains or implies the return type: When the method name clearly communicates the type being returned, var is preferred because the type is already readable from the call itself: var componentType = component.GetType(); var resourceStream = BitmapSelector.GetResourceStream(type, name); TryLoadBitmapFromStream(stream, out var resourceBitmap)
// GOOD — var when type is visible or implied on the line
var designerHostShim = (IDesignerHostShim)designerHost;
var host = this.GetService<IDesignerHost>();
var manager = host.GetExport<ViewModelClientFactoryManager>();
var componentType = component.GetType();
var resourceStream = BitmapSelector.GetResourceStream(componentType, componentType.Name + ".bmp");
service.TryGetValue<AppSettings>(out var settings);
  1. Use var for deeply nested or complex generic types where the full type name is unwieldy:
using var pooledList = ListPool<IComponent>.GetPooledObject();
var result = pooledList.Object;
var (key, value) = dictionary.First();   // tuple deconstruction
  1. Use explicit types when neither the variable name nor the surrounding context reveals the type. If a reader would need to navigate to a method signature to understand what a variable holds, spell the type out.
// REQUIRED — explicit when type is not obvious
CreateViewModelResponse response = session.GetWinFormsEndpoints().DocumentOutline.CreateViewModel(session.Id);
TreeViewHitTestInfo hitTestInfo = _treeView.HitTest(e.Location);
  1. Prefer target-typed new() over var when the type is visible on the left — clean construction without redundancy:
// Before
Dictionary<string, List<int>> map = new Dictionary<string, List<int>>();
var map = new Dictionary<string, List<int>>();

// After
Dictionary<string, List<int>> map = new();
Button saveButton = new();

Do NOT use target-typed new() when the type isn't visible on the same line:

// DO — type is visible on the right, so var is fine:
var map = new Dictionary<string, List<int>>();

// DON'T — _map is a backing field declared elsewhere,
// so the type isn't visible here. Too implicit.
_map = new();
  1. var is always fine for tuple deconstruction:
var (nodes, images) = viewModel.UpdateTreeView(displayStyle);
var (key, value) = dictionary.First();
  1. Using Collection expressions:
// Before
List<string> items = new List<string>();

// After
List<string> items = [];
  • Consider collection expressions also for methods that return collections, e.g.:
// Before
Control[] controls = _view.Controls.Cast<Control>().ToArray();

// After
Control[] controls = [.. _view.Controls.Cast<Control>()];
  • Avoid, however, collection expressions, when constructable array/collection type are necessary in the context, e.g.:
// Be careful! Will not compile, we need a constructable array type in this
// context, so collection initializer syntax is not possible here.
Control CreateErrorControlForMessage(string message) 
   => CreateErrorControl([new InvalidOperationException(message)]);

// In this case we need:
Control CreateErrorControlForMessage(string message) 
   => CreateErrorControl(new[] { new InvalidOperationException(message) });

Null Checking

  • Use is null / is not null — never == null or != null.
  • Use coalesce: value ?? "default", value ??= GetDefault().

Naming and Field Conventions

ElementConvention
private / internal instance fields_camelCase
private static fieldss_camelCase
[ThreadStatic] fieldst_camelCase
ConstantsPascalCase
All other membersPascalCase
  • Never qualify with this. unless strictly necessary to resolve ambiguity.
  • Declare accessibility modifiers explicitly on every type and member.
  • Use the narrowest possible scope — prefer private over internal over public.
  • Mark members static when they do not access instance state.

Formatting and Line Length

Expression-bodied members

Use expression bodies (=>) for single-expression methods and read-only properties. When the total line length would exceed 60 characters, wrap by placing the => on the next line, indented:

// Short — fits on one line
internal int BorderWidth => _borderWidth;

// Long — wrap the arrow to the next line
private bool IsValidSize(Size size)
    => size.Width > 0 && size.Height > 0;

internal string QualifiedName
    => $"{Namespace}.{TypeName}";

Important semantic distinction: public Foo Bar => new Foo(); creates a new instance on every access. public Foo Bar { get; } = new Foo(); creates one instance at construction. Never convert between these forms unless the original semantics were provably wrong.

Braces and blocks

  • Allman style — opening brace on its own line.
  • Insert an empty line after closing braces of control-flow blocks and before return statements.
  • If a comment precedes a line that needs an empty line above it, the empty line goes before the comment.

Ternary operator

Put each branch on its own line unless the whole expression is very short:

Color textColor = e.Item.Enabled
    ? GetDarkModeColor(e.TextColor)
    : GetDarkModeColor(SystemColors.GrayText);

Pattern Matching and Switch Expressions

Prefer switch expressions over switch statements over if-chains:

string result = value switch
{
    > 0 => "Positive",
    < 0 => "Negative",
    _ => "Zero"
};

Use and, or, relational, property, tuple, type, and list patterns where they improve clarity. When converting if-chains that return or assign, a switch expression is almost always clearer.

Readability

  1. Never sacrifice readability for brevity

Prefer extension method call syntax over static helpers when the same operation is available in both forms — extensions read more naturally and reduce visual noise:

// Prefer
Size deviceSize = image.Size.LogicalToDeviceUnits();

// Over
Size deviceSize = DpiHelper.LogicalToDeviceUnits(image.Size);
  1. Prefer inline #pragma or [SuppressMessage]

Use inline #pragma or [SuppressMessage] at the call site over global suppressions, so justification is visible in context.

  1. Named arguments

Use named arguments when passing multiple literals or when the meaning of a parameter isn't clear from the argument expression itself:

// GOOD — named arguments clarify meaning of literals
var errorControl = CreateErrorControlForMessage(
    message: "An unexpected error occurred. Please try again.",
    showRetryButton: true);

Note: When method calls take a lot of space due to a long argument list, consider wrapping the individual arguments on separate lines. If you then decide to use named arguments, use them for every argument to improve readability and consistency:

LongMethodWithManyNamedArguments(
    firstArgument: value1,
    secondArgument: value2,
    thirdArgument: value3,
    fourthArgument: value4);
  1. Wrap dot-chains with more than 2 member accesses — each call goes on its own indented line:
// Fine — 2 or fewer:
var names = items.Where(x => x.IsActive).ToList();

// Wrap — more than 2:
var resul

---

*Content truncated.*

When not to use it

  • Refactoring existing files

Limitations

  • Applies only to new code generation
  • Requires adherence to .editorconfig

How it compares

This provides a set of strict, project-specific generation rules compared to generic code generation.

Compared to similar skills

coding-standards side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
coding-standards (this skill)04moNo flagsBeginner
csharp-developer432moNo flagsAdvanced
csharp-pro94moNo flagsIntermediate
update-roslyn-version22moReviewAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

csharp-developer

zenobi-us

Expert C# developer specializing in modern .NET development, ASP.NET Core, and cloud-native applications. Masters C# 12 features, Blazor, and cross-platform development with emphasis on performance and clean architecture.

43151

csharp-pro

sickn33

Write modern C# code with advanced features like records, pattern matching, and async/await. Optimizes .NET applications, implements enterprise patterns, and ensures comprehensive testing. Use PROACTIVELY for C# refactoring, performance optimization, or complex .NET solutions.

953

update-roslyn-version

dotnet

Guide for updating the Roslyn language server version in the vscode-csharp repository. Use this when asked to update Roslyn, bump the Roslyn version, or upgrade the language server version.

211

orchardcore-module-creator

OrchardCMS

Creates new OrchardCore modules with proper structure, manifest, startup, and patterns. Use when the user needs to create a new module, add content parts, fields, drivers, handlers, or admin functionality.

13

azure-mgmt-apicenter-dotnet

microsoft

Azure API Center SDK for .NET. Centralized API inventory management with governance, versioning, and discovery. Use for creating API services, workspaces, APIs, versions, definitions, environments, deployments, and metadata schemas. Triggers: "API Center", "ApiCenterService", "ApiCenterWorkspace", "ApiCenterApi", "API inventory", "API governance", "API versioning", "API catalog", "API discovery".

12

generator.equals

diegofrata

Guidance for using Generator.Equals — a C# source generator for auto-generating Equals, GetHashCode, operators, and Diff/Inequalities methods via attributes.

00

Search skills

Search the agent skills registry