SuperAPI AI Directory

coding-conventions

Coding & development

View repository

Updated 10-15 22:34

About this skill

Coding Conventions

Overview

This SKILL defines the coding conventions that apply to all .NET projects being developed. Its purpose is to implement code with high readability, maintainability, and performance by actively leveraging the latest features since .NET 8 (C# 12/13/14, .NET 8/9/10).

Scope of Responsibility

This SKILL covers the following scope:

  • Policy for leveraging the latest features of .NET/C# (C# 12/13/14, .NET 8/9/10)
  • Naming conventions (Type, Member, Variable, Parameter)
  • Code layout and formatting
  • Policy for using language features (Type inference, Collection, Exception handling)
  • Best practices for LINQ and lambda expressions
  • Recommended patterns for modern C# syntax

Basic Policy

  • Actively use the latest features since .NET 8 (C# 12/13/14, .NET 8/9/10)
  • Always prioritize the latest features except when backward compatibility is required
  • Avoid outdated language syntax
  • Important: Using the underscore prefix (_field) is absolutely prohibited
  • Important: Omitting braces is absolutely prohibited (omission is not allowed even when it can be written on one line)
  • Follow Microsoft's official coding conventions
  • Maintain consistency and apply the same style across the entire team

Latest .NET/C# Features (by Version)

Actively leverage the major features introduced in each version since .NET 8. Always prioritize the latest features except when backward compatibility is required.

C# 12 (.NET 8) - Official release in November 2023

Primary Constructors

  • Parameters can be defined in a class or struct declaration and used throughout the class
  • Reduces explicit field declarations and simplifies initialization

Good example:

public class Person(string name, int age)
{
    public string Name => name;
    public int Age => age;

    public void Display()
    {
        Console.WriteLine($"{name} is {age} years old");
    }
}

Bad example:

public class Person
{
    private string name;
    private int age;

    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public string Name => name;
    public int Age => age;
}

Collection Expressions

  • Concisely create collections using square brackets and the spread operator
  • Useful when combining multiple collections

Good example:

int[] array = [1, 2, 3, 4, 5];
List<string> list = ["one", "two", "three"];

int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];

// 스프레드 연산자로 결합
int[] combined = [..row0, ..row1];

Default Lambda Parameters

  • Default parameter values can be specified in lambda expressions

Good example:

var incrementBy = (int source, int increment = 1) => source + increment;

Console.WriteLine(incrementBy(5));
Console.WriteLine(incrementBy(5, 3));

Alias Any Type

  • Aliases can be assigned to complex types with the using directive

Good example:

using Point = (int x, int y);
using ProductList = System.Collections.Generic.List<(string Name, decimal Price)>;

Point origin = (0, 0);
ProductList products = [("Product1", 100m), ("Product2", 200m)];

C# 13 (.NET 9) - Official release in November 2024

Params Collections

  • params The modifier can now be used on collection types other than arrays
  • List<T>, Span<T>, ReadOnlySpan<T>, IEnumerable<T> can be used in etc.

Good example:

public void ProcessItems(params List<string> items)
{
    foreach (var item in items)
    {
        Console.WriteLine(item);
    }
}

// 메모리 효율이 중요한 경우
public void ProcessData(params ReadOnlySpan<int> data)
{
    foreach (var value in data)
    {
        Process(value);
    }
}

New Lock Type

  • System.Threading.Lock Implement faster thread synchronization using the type
  • Faster than the existing Monitor -based lock

Good example:

private readonly Lock lockObject = new();

public void UpdateData()
{
    lock (lockObject)
    {
        // Critical section
    }
}

Bad example:

// 기존 object 기반 락 (C# 13에서는 권장되지 않음)
private readonly object lockObject = new();

public void UpdateData()
{
    lock (lockObject)
    {
        // Critical section
    }
}

Partial Properties and Indexers

  • Partial properties and indexers can now be used
  • Definition and implementation can be separated

Good example:

// 정의 부분
public partial class DataModel
{
    public partial string Name { get; set; }
}

// 구현 부분
public partial class DataModel
{
    private string name;

    public partial string Name
    {
        get => name;
        set => name = value ?? throw new ArgumentNullException(nameof(value));
    }
}

Implicit Index Access

  • In object initializers, ^ operator can now be used

Good example:

var countdown = new TimerBuffer
{
    buffer =
    {
        [^1] = 0,
        [^2] = 1,
        [^3] = 2
    }
};

Ref Struct Enhancements

  • ref struct A type can now implement an interface
  • In generic types, ref structcan now be used (allows ref struct constraint)

Good example:

public ref struct SpanWrapper<T> : IEnumerable<T>
{
    private Span<T> span;

    public IEnumerator<T> GetEnumerator()
    {
        foreach (var item in span)
        {
            yield return item;
        }
    }
}

C# 14 (.NET 10) - Scheduled for release in November 2025

Extension Members

  • Implement clean API extensions using Extension Members
  • You can add functionality without polluting the original type

Good example:

extension<TSource>(IEnumerable<TSource> source)
{
    public bool IsEmpty => !source.Any();
    public int Count => source.Count();
}

Field-Backed Properties

  • field Reduce explicit backing fields by using the keyword
  • Validation logic can be written concisely
  • Explicit backing fields using an underscore prefix are absolutely forbidden

Good example:

// C# 14의 field 키워드 사용
public string Name
{
    get;
    set => field = value ?? throw new ArgumentNullException(nameof(value));
}

// 어쩔 수 없이 명시적인 backing field가 필요한 경우에도 언더스코어 없음
private string name;

public string Name
{
    get => name;
    set => name = value ?? throw new ArgumentNullException(nameof(value));
}

Bad example:

// 언더스코어 접두사는 절대 금지
private string _name;

public string Name
{
    get => _name;
    set => _name = value ?? throw new ArgumentNullException(nameof(value));
}

Null-Conditional Assignment

  • ?.Write null checks concisely using
  • Reduce duplicate null checks

Good example:

customer?.Order = GetCurrentOrder();

Bad example:

if (customer != null)
{
    customer.Order = GetCurrentOrder();
}

Implicit Span Conversions

  • In performance-critical code, Span<T>와 ReadOnlySpan<T>is used
  • Use automatic conversion between arrays and span types

Naming Conventions

Pascal Casing

  • Type names (class, record, struct, interface, enum)
  • Public members (properties, methods, events)
  • Namespaces

Good example:

public class CustomerOrder
{
    public string OrderId { get; set; }
    public void ProcessOrder() { }
}

Camel Casing

  • Local variables
  • Method parameters
  • Private fields (Never use an underscore prefix)

Good example:

public class OrderProcessor
{
    // 언더스코어 없음
    private string customerName;

    // 언더스코어 없음
    private int orderCount;

    public void ProcessOrder(string orderId)
    {
        var customerName = GetCustomerName(orderId);
        string processedResult = Process(customerName);
    }
}

Bad example:

public class OrderProcessor
{
    // 언더스코어 접두사는 절대 금지
    private string _customerName;

    // 언더스코어 접두사는 절대 금지
    private int _orderCount;
}

Interface naming

  • Prefix Iis used

Good example:

public interface IOrderProcessor
{
    void Process(Order order);
}

Type parameter naming

  • Prefix Tis used
  • Use meaningful names

Good example:

public class Repository<TEntity> where TEntity : class
{
    public void Add(TEntity entity) { }
}

Code Layout

Indentation

  • Use 4 spaces
  • Do not use tabs

Curly Braces

  • Allman style (place the opening and closing braces on separate lines)
  • Omitting braces is absolutely forbidden (always use braces even when it can be written on one line)

Good example:

public void ProcessOrder(Order order)
{
    if (order != null)
    {
        order.Process();
    }
}

// 1행이라도 중괄호를 사용함
if (isValid)
{
    Execute();
}

for (int i = 0; i < 10; i++)
{
    Process(i);
}

Bad example:

// 중괄호 생략 금지
if (isValid)
    Execute();

// 중괄호 생략 금지
for (int i = 0; i < 10; i++)
    Process(i);

// 중괄호 생략 금지
if (order != null) order.Process();

Line writing

  • Write only one statement per line
  • Write only one declaration per line
  • Put one blank line between method definitions and property definitions

Good example:

public class Order
{
    public string OrderId { get; set; }

    public void Process()
    {
        var result = Validate();
        Execute(result);
    }

    private bool Validate()
    {
        return OrderId != null;
    }
}

Namespaces

  • Use file-scoped namespaces

Good example:

namespace YourProject.Orders;

public class OrderProcessor
{
    // Implementation
}

Bad example:

namespace YourProject.Orders
{
    public class OrderProcessor
    {
        // Implementation
    }
}

using directives

  • Place them outside the namespace declaration
  • Sort them alphabetically

Good example:

using System;
using System.Collections.Generic;
using System.Linq;

namespace YourProject.Orders;

Types and variables

Type specification

  • Language keywords (string, int, bool) are used
  • Runtime types (System.String, System.Int32) is not used

Good example:

string name = "John";
int count = 10;
bool isValid = true;

Bad example:

String name = "John";
Int32 count = 10;
Boolean isValid = true;

Type inference (var)

  • Only when the type is obvious from the assigned content varis used
  • Built-in types are explicitly stated

Good example:

// 명백함
var orders = new List<Order>();

// 명백함
var customer = GetCustomer();

// 기본 타입은 명시
int count = 10;

// 기본 타입은 명시
string name = "John";

Bad example:

// 기본 타입에서 var는 피함
var count = 10;

// 기본 타입에서 var는 피함
var name = "John";

String

String Interpolation

  • Use string interpolation for short string concatenations

Good example:

string message = $"Order {orderId} processed successfully";

Bad example:

string message = "Order " + orderId + " processed successfully";

StringBuilder

  • When appending large amounts of text within a loop, StringBuilderis used

Good example:

var builder = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
    builder.Append($"Line {i}\n");
}

Raw String Literals

  • Prefer Raw String Literals over escape sequences

Good example:

string json = """
{
    "name": "John",
    "age": 30
}
""";

Collection and Object Initialization

Collection Initialization

  • Use Collection Expressions from C# 12 onward (see "C# 12 Latest Features" above)

Object Initializer

  • Use object initializers to simplify creation

Good example:

var customer = new Customer
{
    Name = "John",
    Email = "john@example.com"
};

Exception Handling

Catching Specific Exceptions

  • General System.Exception Catch specific exceptions instead of

Good example:

try
{
    ProcessOrder(order);
}
catch (ArgumentNullException ex)
{
    Logger.Error("Order is null", ex);
}

Bad example:

try
{
    ProcessOrder(order);
}
catch (Exception ex) // 너무 일반적임
{
    Logger.Error("Error", ex);
}

using 문

  • Instead of try-finally, use the using statement

Good example:

using var connection = new SqlConnection(connectionString);
connection.Open();
// Process

Bad example:

SqlConnection connection = null;
try
{
    connection = new SqlConnection(connectionString);
    connection.Open();
    // Process
}
finally
{
    connection?.Dispose();
}

LINQ

Meaningful Variable Names

  • Use meaningful names for query variables

Good example:

var activeCustomers = from customer in customers
                      where customer.IsActive
                      select customer;

Early Filtering

  • where Filter data early using the clause

Good example:

var result = customers
    .Where(c => c.IsActive)
    .Select(c => c.Name)
    .ToList();

Implicit Typing

  • Use implicit typing in LINQ declarations

Good example:

var query = from customer in customers
            where customer.IsActive
            select customer;

Lambda Expressions

Event Handlers

  • Use lambda expressions for handlers that do not require removal

Good example:

button.Click += (s, e) => ProcessClick();

Parameter Modifiers

  • Use modifiers while maintaining type inference by leveraging C# 14 features

Good example:

TryParse<int> parse = (text, out result) => int.TryParse(text, out result);

Comments

Single-line Comments

  • For concise explanations, use //uses
  • Put one space after the comment delimiter
  • Comments must be written on their own line (do not write them on the same line as code)
  • Put one blank line before comments

Good example:

// 고객 주문을 처리함
ProcessOrder(order);

var processor = new OrderProcessor();

// 주문을 실행함
var result = processor.ProcessOrder(order);

Bad example:

ProcessOrder(order); // 고객 주문을 처리함 (코드와 같은 행은 금지)

var processor = new OrderProcessor();
// 이 행의 앞에 빈 행이 없음 (나쁜 예)
var result = processor.ProcessOrder(order);

XML Documentation

  • Use XML documentation for public members

Good example:

/// <summary>
/// 지정된 주문을 처리함
/// </summary>
/// <param name="order">처리할 주문</param>
/// <returns>처리 결과</returns>
public bool ProcessOrder(Order order)
{
    // Implementation
}

Static Members

Calling by Class Name

  • Call static members through the class name

Good example:

var result = OrderProcessor.ProcessOrder(order);

Bad example:

var processor = new OrderProcessor();

// 정적 메서드를 인스턴스를 통해 호출하는 것은 오해의 소지가 있음
var result = processor.ProcessOrder(order);

Checklist

Before Writing Code

  • Are you aware of the latest features of .NET/C# (C# 12/13/14)
  • The project's target framework is set to .NET 8 or later
  • understands naming conventions

While writing code

Required rules:

  • Never used underscore prefixes
  • Did not omit braces (always used them even for a single line)
  • Comments were always written on their own line (not on the same line as code)
  • Inserted one blank line before comments

C# 12 and later features:

  • Using Primary Constructors (where applicable)
  • Using Collection Expressions
  • Utilizing Default Lambda Parameters (where applicable)
  • Used Alias Any Type to alias complex types (where applicable)

C# 13 and later features:

  • Using Params Collections (where applicable)
  • Using the New Lock Type (when thread synchronization is needed)
  • Utilizing Partial Properties and Indexers (where applicable)
  • Using Implicit Index Access in object initializers (where applicable)

C# 14 and later features:

  • field Used the keyword to concisely write backing fields
  • Utilizing Extension Members (where applicable)
  • Utilizing Null-Conditional Assignment
  • Using Lambda Parameters with Modifiers (where applicable)

Basic rules:

  • Using file-scoped namespaces
  • Language keywords (string, int) are used
  • varis used appropriately (only when the type is obvious)
  • Using string interpolation
  • Using Raw String Literals (where applicable)
  • Using Object Initializers
  • using Using the statement
  • Catching specific exceptions
  • Performing early filtering in LINQ expressions
  • Using meaningful variable names
  • Comments are concise and clear
  • Documented public members with XML documentation
  • Placed braces in Allman style
  • Using 4 spaces for indentation

After writing code

  • Code was written in a consistent style
  • Utilizing the latest features of .NET 8 and later (C# 12/13/14)
  • Following naming conventions
  • Code is highly readable and easy to maintain