Back to Skills

csharp-code-style

majiayu000
Updated Today
1 views
58
9
58
View on GitHub
Developmentgeneral

About

This skill provides C# coding standards based on POCU conventions, including naming rules like mPascalCase for private members and prefixes for booleans/enums. Use it proactively during code reviews, refactoring, or when establishing project style guidelines to ensure consistent C# 9.0+ code organization and patterns.

Quick Install

Claude Code

Recommended
Plugin CommandRecommended
/plugin add https://github.com/majiayu000/claude-skill-registry
Git CloneAlternative
git clone https://github.com/majiayu000/claude-skill-registry.git ~/.claude/skills/csharp-code-style

Copy and paste this command in Claude Code to install this skill

Documentation

C# Code Style Guide

Overview

C# 코딩 표준 (POCU 기반, C# 9.0 기준)

Core Topics:

  • 명명 규칙 (m접두어, b접두어, E/S접두어)
  • 코드 작성 규칙
  • 클래스 구조 순서
  • C# 9.0 패턴

Naming Conventions

Quick Reference

ElementConventionExample
ClassPascalCasePlayerManager, OrderService
StructSPascalCaseSUserID, SPlayerData
InterfaceIPascalCaseIDisposable, IOrderService
EnumEPascalCaseEDirection, EOrderStatus
Method (public)PascalCase (동사+명사)GetAge(), ProcessOrder()
Method (private)camelCasegetAge(), processOrder()
PropertyPascalCaseName, OrderID
Private FieldmPascalCasemAge, mOrderRepository
Local VariablecamelCasetotalAmount, isValid
ParametercamelCasecustomerId, orderDate
ConstantALL_CAPSMAX_RETRY_COUNT, DEFAULT_TIMEOUT
Static readonlyALL_CAPSMY_CONST_OBJECT
Boolean VariablebCamelCase / mbPascalCasebFired, mbIsEnabled
Boolean PropertyIs/Has/Can/ShouldIsFired, HasChildren

Private Member Pattern

public class OrderService
{
    // Private fields: m + PascalCase
    private readonly IOrderRepository mOrderRepository;
    private readonly ILogger mLogger;
    private int mRetryCount;
    private bool mbIsProcessing;  // boolean: mb prefix

    // Constructor parameter: camelCase (no prefix)
    public OrderService(IOrderRepository orderRepository, ILogger logger)
    {
        mOrderRepository = orderRepository;
        mLogger = logger;
    }

    // Public method: PascalCase
    public Order GetOrder(int orderId)
    {
        return getOrderInternal(orderId);
    }

    // Private method: camelCase
    private Order getOrderInternal(int orderId)
    {
        return mOrderRepository.Find(orderId);
    }
}

Enum and Struct Prefixes

// Enum: E prefix
public enum EDirection
{
    None,
    North,
    South,
    East,
    West
}

// Bit flags enum: Flags suffix
[Flags]
public enum EVisibilityFlags
{
    None = 0,
    Visible = 1,
    Hidden = 2,
    Collapsed = 4
}

// Struct: S prefix (readonly struct는 제외 가능)
public struct SUserID
{
    public int Value { get; }
}

// readonly record struct: S prefix 불필요
public readonly record struct UserID(int Value);

Nullable Naming

// Nullable parameter: OrNull suffix
public Animation GetAnimation(string nameOrNull)
{
    if (nameOrNull == null)
    {
        return DefaultAnimation;
    }
    return mAnimations[nameOrNull];
}

// Nullable return: OrNull suffix
public string GetNameOrNull()
{
    return mbHasName ? mName : null;
}

// Recursive function: Recursive suffix
public int FibonacciRecursive(int n)
{
    if (n <= 1)
    {
        return n;
    }
    return FibonacciRecursive(n - 1) + FibonacciRecursive(n - 2);
}

Code Writing Rules

Prohibited Patterns

// [WRONG] var keyword
var order = GetOrder(1);
var items = new List<Item>();

// [CORRECT] Explicit type
Order order = GetOrder(1);
List<Item> items = new List<Item>();

// [WRONG] Null coalescing operator (??)
string name = inputName ?? "Default";

// [CORRECT] Explicit null check
string name;
if (inputName != null)
{
    name = inputName;
}
else
{
    name = "Default";
}

// [WRONG] using declaration (C# 8.0)
using FileStream stream = new FileStream(path, FileMode.Open);

// [CORRECT] using statement
using (FileStream stream = new FileStream(path, FileMode.Open))
{
    // ...
}

// [WRONG] target-typed new()
List<Order> orders = new();

// [CORRECT] Explicit type
List<Order> orders = new List<Order>();

// [WRONG] Async suffix
public async Task<Order> GetOrderAsync(int id);

// [CORRECT] No Async suffix
public async Task<Order> GetOrder(int id);

// [WRONG] inline out declaration
if (int.TryParse(input, out int result))

// [CORRECT] separate out declaration
int result;
if (int.TryParse(input, out result))

Required Patterns

// Always use braces, even for single line
if (condition)
{
    DoSomething();
}

// Float literals with f suffix
float value = 0.5f;
float another = 1.0f;

// Switch must have default case
switch (status)
{
    case EStatus.Active:
        Process();
        break;
    case EStatus.Inactive:
        Skip();
        break;
    default:
        Debug.Fail("Unknown status");
        break;
}

// Debug.Assert for all assumptions
Debug.Assert(order != null, "Order should not be null");
Debug.Assert(count > 0, "Count must be positive");

// Properties instead of getter/setter methods
// [WRONG]
public int GetAge() { return mAge; }
public void SetAge(int age) { mAge = age; }

// [CORRECT] (.NET 5+ only - NOT available in Unity)
public int Age { get; private init; }

// [CORRECT] (Unity compatible)
public int Age { get; private set; }

C# 9.0 Patterns

Unity Limitation: init accessor is NOT available in Unity (requires .NET 5+ runtime). See Modern Patterns Reference for details and alternatives.

// private init (C# 9.0) - .NET 5+ only, NOT available in Unity
public class Customer
{
    public string Name { get; private init; }  // Use 'private set' in Unity
    public string Email { get; private init; }
}

// Record for immutable data
public record OrderDto(int Id, string CustomerName, decimal TotalAmount);

// Pattern matching switch expression (available in Unity)
public string GetStatusMessage(EOrderStatus status)
{
    return status switch
    {
        EOrderStatus.Pending => "Order is pending",
        EOrderStatus.Completed => "Order completed",
        _ => throw new ArgumentOutOfRangeException(nameof(status))
    };
}

Class Structure Order

public class OrderService : IOrderService
{
    // 1. Constants
    private const int MAX_RETRY_COUNT = 3;
    public static readonly TimeSpan DEFAULT_TIMEOUT = TimeSpan.FromSeconds(30);

    // 2. Private member variables
    private readonly IOrderRepository mOrderRepository;
    private readonly ILogger mLogger;
    private int mProcessedCount;
    private bool mbIsInitialized;

    // 3. Properties (with private member above if needed)
    public int ProcessedCount => mProcessedCount;
    public bool IsInitialized => mbIsInitialized;

    // 4. Constructors
    public OrderService(IOrderRepository orderRepository, ILogger logger)
    {
        mOrderRepository = orderRepository;
        mLogger = logger;
    }

    // 5. Public methods
    public Order GetOrder(int id)
    {
        Debug.Assert(id > 0, "ID must be positive");
        return mOrderRepository.Find(id);
    }

    public void ProcessOrder(Order order)
    {
        validateOrder(order);
        processInternal(order);
    }

    // 6. Private methods
    private void validateOrder(Order order)
    {
        Debug.Assert(order != null);
    }

    private void processInternal(Order order)
    {
        // Implementation
    }
}

File Organization

  • 각 클래스는 독립된 파일에 작성
  • 파일명 = 클래스명 (정확히 일치)
  • Partial 클래스: ClassName.SubName.cs

Reference Documentation

Naming Conventions

Complete naming rules:

  • m/mb 접두어 상세
  • E/S 접두어 규칙
  • OrNull 접미어 패턴
  • ALL_CAPS 상수 규칙

Modern Patterns

C# 9.0 language features:

  • Records and init-only properties
  • Pattern matching
  • File-scoped namespaces (C# 10)
  • 금지 패턴 상세

Error Handling

Error handling patterns:

  • Debug.Assert 사용
  • 경계에서만 예외 처리
  • null 반환/매개변수 회피
  • 유효성 검증 패턴

Key Principles

  1. 가독성 최우선: 명확하고 이해하기 쉬운 코드 작성
  2. 명시적 타입: var 사용 금지, 타입 명시
  3. Null 안전: OrNull 접미어로 nullable 명시
  4. Assertion: 모든 가정에 Debug.Assert 사용
  5. 경계 검증: 외부 데이터는 경계에서만 검증
  6. Use init: Prefer C# 9.0 private init (.NET 5+ only, NOT available in Unity)
  7. No Emoji: 코드 예제 및 문서에서 이모지 사용 금지, 텍스트 태그 사용 ([WRONG], [CORRECT], [CAUTION])

GitHub Repository

majiayu000/claude-skill-registry
Path: skills/csharp-code-style

Related Skills

algorithmic-art

Meta

This Claude Skill creates original algorithmic art using p5.js with seeded randomness and interactive parameters. It generates .md files for algorithmic philosophies, plus .html and .js files for interactive generative art implementations. Use it when developers need to create flow fields, particle systems, or other computational art while avoiding copyright issues.

View skill

subagent-driven-development

Development

This skill executes implementation plans by dispatching a fresh subagent for each independent task, with code review between tasks. It enables fast iteration while maintaining quality gates through this review process. Use it when working on mostly independent tasks within the same session to ensure continuous progress with built-in quality checks.

View skill

executing-plans

Design

Use the executing-plans skill when you have a complete implementation plan to execute in controlled batches with review checkpoints. It loads and critically reviews the plan, then executes tasks in small batches (default 3 tasks) while reporting progress between each batch for architect review. This ensures systematic implementation with built-in quality control checkpoints.

View skill

cost-optimization

Other

This Claude Skill helps developers optimize cloud costs through resource rightsizing, tagging strategies, and spending analysis. It provides a framework for reducing cloud expenses and implementing cost governance across AWS, Azure, and GCP. Use it when you need to analyze infrastructure costs, right-size resources, or meet budget constraints.

View skill