본문으로 건너뛰기
cccskills
무료GitHub에 공개

dotnet-csharp-coding-standards

Defines baseline C# conventions loaded first -- naming, file layout, style rules.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md13.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

dotnet-csharp-coding-standards

Modern .NET coding standards based on Microsoft Framework Design Guidelines and C# Coding Conventions. This skill covers naming, file organization, and code style rules that agents should follow when generating or reviewing C# code.

Activation Guidance

Load this skill by default for any task that plans, designs, generates, modifies, or reviews C#/.NET code. Do not wait for explicit user wording such as "coding standards", "style", or "conventions". If code will be produced, this skill should be active before implementation starts. This skill is a baseline dependency that should be loaded before domain-specific C#/.NET skills.

Cross-references: [skill:dotnet-csharp-modern-patterns] for language feature usage, [skill:dotnet-csharp-async-patterns] for async naming conventions, [skill:dotnet-solid-principles] for SOLID, DRY, and SRP design principles at the class and interface level.

Scope

  • Naming conventions (PascalCase, camelCase, I-prefix for interfaces)
  • File organization and namespace conventions
  • Code style rules (expression bodies, using directives, var usage)
  • EditorConfig integration for style enforcement

Out of scope

  • Language feature patterns (records, pattern matching) -- see [skill:dotnet-csharp-modern-patterns]
  • Async naming and await conventions -- see [skill:dotnet-csharp-async-patterns]
  • SOLID/DRY design principles -- see [skill:dotnet-solid-principles]
  • Code smells and anti-patterns -- see [skill:dotnet-csharp-code-smells]

Naming Conventions

General Rules

ElementConventionExample
NamespacesPascalCase, dot-separatedMyCompany.MyProduct.Core
Classes, Records, StructsPascalCaseOrderService, OrderSummary
InterfacesI + PascalCaseIOrderRepository
MethodsPascalCaseGetOrderAsync
PropertiesPascalCaseOrderDate
EventsPascalCaseOrderCompleted
Public constantsPascalCaseMaxRetryCount
Private fields_camelCase_orderRepository
Parameters, localscamelCaseorderId, totalAmount
Type parametersT or T + PascalCaseT, TKey, TValue
Enum membersPascalCaseOrderStatus.Pending

Async Method Naming

Suffix async methods with Async:


// Correct
public Task<Order> GetOrderAsync(int id);
public ValueTask SaveChangesAsync(CancellationToken ct);

// Wrong
public Task<Order> GetOrder(int id);      // missing Async suffix
public Task<Order> GetOrderTask(int id);  // wrong suffix

```text

Exception: Event handlers and interface implementations where the framework does not use the `Async` suffix (e.g.,
ASP.NET Core middleware `InvokeAsync` is already named by the framework).

### Boolean Naming

Prefix booleans with `is`, `has`, `can`, `should`, or similar:

```csharp

public bool IsActive { get; set; }
public bool HasOrders { get; }
public bool CanDelete(Order order);

```csharp

### Collection Naming

Use plural nouns for collections:

```csharp

public IReadOnlyList<Order> Orders { get; }    // not OrderList
public Dictionary<string, int> CountsByName { get; } // descriptive

```csharp

---

## File Organization

### One Type Per File

Each top-level type (class, record, struct, interface, enum) should be in its own file, named exactly as the type.
Nested types stay in the containing type's file.

```text

OrderService.cs        -> public class OrderService
IOrderRepository.cs    -> public interface IOrderRepository
OrderStatus.cs         -> public enum OrderStatus
OrderSummary.cs        -> public record OrderSummary

```csharp

### File-Scoped Namespaces

Always use file-scoped namespaces (C# 10+):

```csharp

// Correct
namespace MyApp.Services;

public class OrderService { }

// Avoid: block-scoped namespace adds unnecessary indentation
namespace MyApp.Services
{
    public class OrderService { }
}

```text

### Using Directives

Place `using` directives at the top of the file, outside the namespace. With `<ImplicitUsings>enable</ImplicitUsings>`
(default in modern .NET), common namespaces are already imported. Only add explicit `using` statements for namespaces
not covered by implicit usings.

Order of `using` directives:

1. `System.*` namespaces
2. Third-party namespaces
3. Project namespaces

### Directory Structure

Organize by feature or layer, matching namespace hierarchy:

```text

src/MyApp/
  Features/
    Orders/
      OrderService.cs
      IOrderRepository.cs
      OrderEndpoints.cs
    Users/
      UserService.cs
  Infrastructure/
    Persistence/
      OrderRepository.cs

```csharp

---

## Code Style

### Braces

Always use braces for control flow, even for single-line bodies:

```csharp

// Correct
if (order.IsValid)
{
    Process(order);
}

// Avoid
if (order.IsValid)
    Process(order);

```text

### Expression-Bodied Members

Use expression bodies for single-expression members:

```csharp

// Properties
public string FullName => $"{FirstName} {LastName}";

// Methods (single expression only)
public override string ToString() => $"Order #{Id}";

// Avoid for multi-statement methods -- use block body instead

```text

### `var` Usage

Use `var` when the type is obvious from the right-hand side:

```csharp

// Type is obvious: use var
var orders = new List<Order>();
var customer = GetCustomerById(id);
var name = "Alice";

// Type is not obvious: use explicit type
IOrderRepository repo = serviceProvider.GetRequiredService<IOrderRepository>();
decimal total = CalculateTotal(items);

```text

### Null Handling

Prefer pattern matching over null checks:

```csharp

// Preferred
if (order is not null) { }
if (order is { Status: OrderStatus.Active }) { }

// Acceptable
if (order != null) { }

// Avoid
if (order is object) { }
if (!(order is null)) { }

```text

Use null-conditional and null-coalescing operators:

```csharp

var name = customer?.Name ?? "Unknown";
var orders = customer?.Orders ?? [];
items ??= [];

```csharp

### String Handling

Prefer string interpolation over concatenation or `string.Format`:

```csharp

// Preferred
var message = $"Order {orderId} totals {total:C2}";

// For complex interpolations, use raw string literals (C# 11+)
var json = $$"""
    {
        "id": {{orderId}},
        "name": "{{name}}"
    }
    """;

// Avoid
var message = string.Format("Order {0} totals {1:C2}", orderId, total);
var message = "Order " + orderId + " totals " + total.ToString("C2");

```text

---

## Access Modifiers

Always specify access modifiers explicitly. Do not rely on defaults:

```csharp

// Correct
public class OrderService
{
    private readonly IOrderRepository _repo;
    internal void ProcessBatch() { }
}

// Avoid: implicit internal class, implicit private field
class OrderService
{
    readonly IOrderRepository _repo;
}

```text

### Modifier Order

Follow the standard order:

```text

access (public/private/protected/internal) -> static -> extern -> new ->
virtual/abstract/override/sealed -> readonly -> volatile -> async -> partial

```text

```csharp

public static readonly int MaxSize = 100;
protected virtual async Task<Order> LoadAsync() => await repo.GetDefaultAsync();
public sealed override string ToString() => Name;

```csharp

---

## Type Design

These conventions implement SOLID and DRY principles at the code level. For comprehensive coverage with anti-patterns
and fixes, see [skill:dotnet-solid-principles].

### Seal Classes by Default

Seal classes that are not designed for inheritance. This improves performance (devirtualization) and communicates
intent:

```csharp

public sealed class OrderService(IOrderRepository repo)
{
    // Not designed for inheritance
}

```text

Only leave classes unsealed when you explicitly design them as base classes.

### Prefer Composition Over Inheritance

```csharp

// Preferred: composition
public sealed class OrderProcessor(IValidator validator, INotifier notifier)
{
    public async Task ProcessAsync(Order order)
    {
        await validator.ValidateAsync(order);
        await notifier.NotifyAsync(order);
    }
}

// Avoid: deep inheritance hierarchies
public class BaseProcessor { }
public class ValidatingProcessor : BaseProcessor { }
public class NotifyingValidatingProcessor : ValidatingProcessor { }

```text

### Interface Segregation

Keep interfaces focused. Prefer multiple small interfaces over one large one:

```csharp

// Preferred
public interface IOrderReader
{
    Task<Order?> GetByIdAsync(int id, CancellationToken ct = default);
    Task<IReadOnlyList<Order>> GetAllAsync(CancellationToken ct = default);
}

public interface IOrderWriter
{
    Task<Order> CreateAsync(Order order, CancellationToken ct = default);
    Task UpdateAsync(Order order, CancellationToken ct = default);
}

// Avoid: one large interface with unrelated responsibilities
public interface IOrderRepository : IOrderReader, IOrderWriter { }

```text

---

## CancellationToken Conventions

Accept `CancellationToken` as the last parameter in async methods. Use `default` as the default value for optional
tokens:

```csharp

public async Task<Order> GetOrderAsync(int id, CancellationToken ct = default)
{
    return await _repo.GetByIdAsync(id, ct);
}

```text

Always forward the token to downstream async calls. Never ignore a received `CancellationToken`.

---

## XML Documentation

Add XML docs to public API surfaces. Keep them concise:

```csharp

/// <summary>
/// Retrieves an order by its unique identifier.
/// </summary>
/// <param name="id">The order identifier.</param>
/// <param name="ct">Cancellation token.</param>
/// <returns>The order, or <see langword="null"/> if not found.</returns>
public Task<Order?> GetByIdAsync(int id, CancellationToken ct = default);

```text

Do not add XML docs to:

- Private or internal members (unless it's a library's `InternalsVisibleTo` API)
- Self-evident members (e.g., `public string Name { get; }`)
- Test methods

---

## Analyzer Enforcement

Configure these analyzers in `Directory.Build.props` or `.editorconfig` to enforce standards automatically:

```xml

<PropertyGroup>
  <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
  <AnalysisLevel>latest-all</AnalysisLevel>
  <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

```text

Key `.editorconfig` rules for C# style:

```ini

[*.cs]
csharp_style_namespace_declarations = file_scoped:warning
csharp_prefer_braces = true:warning
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
dotnet_style_require_accessibility_modifiers = always:warning
csharp_style_prefer_pattern_matching = true:suggestion

```csharp

See [skill:dotnet-add-analyzers] for full analyzer configuration.

---

## Knowledge Sources

Conventions in this skill are grounded in publicly available content from:

- **Microsoft Framework Design Guidelines** -- The canonical reference for .NET naming, type design, and API surface
  conventions. Source: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/
- **C# Language Design Notes (Mads Torgersen et al.)** -- Design rationale behind C# language features that affect
  coding standards. Key decisions relevant to this skill: file-scoped namespaces (reducing nesting for readability),
  pattern matching over type checks (expressiveness), `required` members (compile-time initialization safety), and `var`
  usage guidelines (readability-first). The language design team explicitly chose these features to reduce ceremony
  while maintaining safety. Source: https://github.com/dotnet/csharplang/tree/main/meetings

> **Note:** This skill applies publicly documented design rationale. It does not represent or speak for the named
> sources.



## Code Navigation (Serena MCP)

**Primary approach:** Use Serena symbol operations for efficient code navigation:

1. **Find definitions**: `serena_find_symbol` instead of text search
2. **Understand structure**: `serena_get_symbols_overview` for file organization
3. **Track references**: `serena_find_referencing_symbols` for impact analysis
4. **Precise edits**: `serena_replace_symbol_body` for clean modifications

**When to use Serena vs traditional tools:**
- ✅ **Use Serena**: Navigation, refactoring, dependency analysis, precise edits
- ✅ **Use Read/Grep**: Reading full files, pattern matching, simple text operations
- ✅ **Fallback**: If Serena unavailable, traditional tools work fine

**Example workflow:**
```text
# Instead of:
Read: src/Services/OrderService.cs
Grep: "public void ProcessOrder"

# Use:
serena_find_symbol: "OrderService/ProcessOrder"
serena_get_symbols_overview: "src/Services/OrderService.cs"
```
## References

- [Framework Design Guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/)
- [C# Coding Conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions)
- [C# Identifier Naming Rules](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/identifier-names)
- [.editorconfig for .NET](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options)
- [C# Language Design Notes](https://github.com/dotnet/csharplang/tree/main/meetings)

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Patterns and techniques for evaluating and improving AI agent outputs.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

rudironsoni/Synaxis22026년 3월 17일 업데이트

Comprehensive AI prompt engineering safety review and improvement prompt. Analyzes prompts for safety, bias, security vulnerabilities, and effectiveness while providing detailed improvement recommendations.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

rudironsoni/Synaxis22026년 3월 17일 업데이트

Use when user requests research requiring multiple sources, comprehensive analysis, or synthesis across topics - technical research, domain knowledge gathering, market analysis, or learning about complex subjects

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

rudironsoni/Synaxis22026년 3월 17일 업데이트

deep-wiki

무료

AI-powered wiki generation for code repositories with commands, agents, and skills

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

rudironsoni/Synaxis22026년 3월 17일 업데이트

Use when building .NET 10 or C# 14 applications; when using minimal APIs, modular monolith patterns, or feature folders; when implementing HTTP resilience, Options pattern, Channels, or validation; when seeing outdated patterns like old extension method syntax

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

rudironsoni/Synaxis22026년 3월 17일 업데이트

Implements accessible .NET UI. SemanticProperties, ARIA, AutomationPeer, testing per platform.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

rudironsoni/Synaxis22026년 3월 17일 업데이트

rudironsoni의 스킬 모두 보기

이 스킬의 문제 신고