csharp-code-style
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseC# Code Style Guide
C#代码风格指南
Overview
概述
C# 코딩 표준 (POCU 기반, C# 9.0 기준)
Core Topics:
- 명명 규칙 (m접두어, b접두어, E/S접두어)
- 코드 작성 규칙
- 클래스 구조 순서
- C# 9.0 패턴
C#编码标准(基于POCU,以C# 9.0为基准)
核心主题:
- 命名规则(m前缀、b前缀、E/S前缀)
- 代码编写规则
- 类结构顺序
- C# 9.0模式
Naming Conventions
命名规范
Quick Reference
快速参考
| Element | Convention | Example |
|---|---|---|
| Class | PascalCase | |
| Struct | SPascalCase | |
| Interface | IPascalCase | |
| Enum | EPascalCase | |
| Method (public) | PascalCase (동사+명사) | |
| Method (private) | camelCase | |
| Property | PascalCase | |
| Private Field | mPascalCase | |
| Local Variable | camelCase | |
| Parameter | camelCase | |
| Constant | ALL_CAPS | |
| Static readonly | ALL_CAPS | |
| Boolean Variable | bCamelCase / mbPascalCase | |
| Boolean Property | Is/Has/Can/Should | |
| 元素 | 规范 | 示例 |
|---|---|---|
| 类 | PascalCase | |
| 结构体 | SPascalCase | |
| 接口 | IPascalCase | |
| 枚举 | EPascalCase | |
| 方法(公共) | PascalCase(动词+名词) | |
| 方法(私有) | camelCase | |
| 属性 | PascalCase | |
| 私有字段 | mPascalCase | |
| 局部变量 | camelCase | |
| 参数 | camelCase | |
| 常量 | ALL_CAPS | |
| 静态只读 | ALL_CAPS | |
| 布尔变量 | bCamelCase / mbPascalCase | |
| 布尔属性 | Is/Has/Can/Should | |
Private Member Pattern
私有成员模式
csharp
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);
}
}csharp
public class OrderService
{
// 私有字段: m + PascalCase
private readonly IOrderRepository mOrderRepository;
private readonly ILogger mLogger;
private int mRetryCount;
private bool mbIsProcessing; // 布尔类型: mb前缀
// 构造函数参数: camelCase(无前缀)
public OrderService(IOrderRepository orderRepository, ILogger logger)
{
mOrderRepository = orderRepository;
mLogger = logger;
}
// 公共方法: PascalCase
public Order GetOrder(int orderId)
{
return getOrderInternal(orderId);
}
// 私有方法: camelCase
private Order getOrderInternal(int orderId)
{
return mOrderRepository.Find(orderId);
}
}Enum and Struct Prefixes
枚举与结构体前缀
csharp
// 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);csharp
// 枚举: E前缀
public enum EDirection
{
None,
North,
South,
East,
West
}
// 位标志枚举: Flags后缀
[Flags]
public enum EVisibilityFlags
{
None = 0,
Visible = 1,
Hidden = 2,
Collapsed = 4
}
// 结构体: S前缀(readonly struct可省略)
public struct SUserID
{
public int Value { get; }
}
// readonly record struct: 无需S前缀
public readonly record struct UserID(int Value);Nullable Naming
可空类型命名
csharp
// 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);
}csharp
// 可空参数: OrNull后缀
public Animation GetAnimation(string nameOrNull)
{
if (nameOrNull == null)
{
return DefaultAnimation;
}
return mAnimations[nameOrNull];
}
// 可空返回值: OrNull后缀
public string GetNameOrNull()
{
return mbHasName ? mName : null;
}
// 递归函数: Recursive后缀
public int FibonacciRecursive(int n)
{
if (n <= 1)
{
return n;
}
return FibonacciRecursive(n - 1) + FibonacciRecursive(n - 2);
}Code Writing Rules
代码编写规则
Prohibited Patterns
禁止模式
csharp
// [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))csharp
// [错误] var关键字
var order = GetOrder(1);
var items = new List<Item>();
// [正确] 显式类型
Order order = GetOrder(1);
List<Item> items = new List<Item>();
// [错误] 空合并运算符(??)
string name = inputName ?? "Default";
// [正确] 显式空检查
string name;
if (inputName != null)
{
name = inputName;
}
else
{
name = "Default";
}
// [错误] using声明(C# 8.0)
using FileStream stream = new FileStream(path, FileMode.Open);
// [正确] using语句
using (FileStream stream = new FileStream(path, FileMode.Open))
{
// ...
}
// [错误] 目标类型new()
List<Order> orders = new();
// [正确] 显式类型
List<Order> orders = new List<Order>();
// [错误] Async后缀
public async Task<Order> GetOrderAsync(int id);
// [正确] 无Async后缀
public async Task<Order> GetOrder(int id);
// [错误] 内联out声明
if (int.TryParse(input, out int result))
// [正确] 单独out声明
int result;
if (int.TryParse(input, out result))Required Patterns
强制模式
csharp
// 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; }csharp
// 即使单行也要使用大括号
if (condition)
{
DoSomething();
}
// 浮点字面量添加f后缀
float value = 0.5f;
float another = 1.0f;
// Switch语句必须包含default分支
switch (status)
{
case EStatus.Active:
Process();
break;
case EStatus.Inactive:
Skip();
break;
default:
Debug.Fail("Unknown status");
break;
}
// 所有假设都使用Debug.Assert
Debug.Assert(order != null, "Order should not be null");
Debug.Assert(count > 0, "Count must be positive");
// 使用属性而非getter/setter方法
// [错误]
public int GetAge() { return mAge; }
public void SetAge(int age) { mAge = age; }
// [正确](仅.NET 5+可用 - Unity不支持)
public int Age { get; private init; }
// [正确](兼容Unity)
public int Age { get; private set; }C# 9.0 Patterns
C# 9.0模式
Unity Limitation:accessor is NOT available in Unity (requires .NET 5+ runtime). See Modern Patterns Reference for details and alternatives.init
csharp
// 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))
};
}Unity限制:访问器在Unity中不可用(需要.NET 5+运行时)。 详情及替代方案请参考现代模式参考。init
csharp
// private init(C# 9.0) - 仅.NET 5+可用,Unity不支持
public class Customer
{
public string Name { get; private init; } // 在Unity中使用'private set'
public string Email { get; private init; }
}
// 用于不可变数据的Record
public record OrderDto(int Id, string CustomerName, decimal TotalAmount);
// 模式匹配switch表达式(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
类结构顺序
csharp
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
}
}csharp
public class OrderService : IOrderService
{
// 1. 常量
private const int MAX_RETRY_COUNT = 3;
public static readonly TimeSpan DEFAULT_TIMEOUT = TimeSpan.FromSeconds(30);
// 2. 私有成员变量
private readonly IOrderRepository mOrderRepository;
private readonly ILogger mLogger;
private int mProcessedCount;
private bool mbIsInitialized;
// 3. 属性(如需对应私有成员则放在其上方)
public int ProcessedCount => mProcessedCount;
public bool IsInitialized => mbIsInitialized;
// 4. 构造函数
public OrderService(IOrderRepository orderRepository, ILogger logger)
{
mOrderRepository = orderRepository;
mLogger = logger;
}
// 5. 公共方法
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 void validateOrder(Order order)
{
Debug.Assert(order != null);
}
private void processInternal(Order order)
{
// 实现逻辑
}
}File Organization
文件组织
- 각 클래스는 독립된 파일에 작성
- 파일명 = 클래스명 (정확히 일치)
- Partial 클래스:
ClassName.SubName.cs
- 每个类独立编写在单独文件中
- 文件名=类名(完全一致)
- 分部类:
ClassName.SubName.cs
Reference Documentation
参考文档
Naming Conventions
命名规范
Complete naming rules:
- m/mb 접두어 상세
- E/S 접두어 규칙
- OrNull 접미어 패턴
- ALL_CAPS 상수 규칙
完整命名规则:
- 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)
- 금지 패턴 상세
C# 9.0语言特性:
- Record与init-only属性
- 模式匹配
- 文件作用域命名空间(C# 10)
- 禁止模式详情
Error Handling
错误处理
Error handling patterns:
- Debug.Assert 사용
- 경계에서만 예외 처리
- null 반환/매개변수 회피
- 유효성 검증 패턴
错误处理模式:
- Debug.Assert使用
- 仅在边界处理异常
- 避免空值返回/参数
- 验证模式
Key Principles
核心原则
- 가독성 최우선: 명확하고 이해하기 쉬운 코드 작성
- 명시적 타입: 사용 금지, 타입 명시
var - Null 안전: OrNull 접미어로 nullable 명시
- Assertion: 모든 가정에 Debug.Assert 사용
- 경계 검증: 외부 데이터는 경계에서만 검증
- Use init: Prefer C# 9.0 private init (.NET 5+ only, NOT available in Unity)
- No Emoji: 코드 예제 및 문서에서 이모지 사용 금지, 텍스트 태그 사용 ([WRONG], [CORRECT], [CAUTION])
- 可读性优先: 编写清晰易懂的代码
- 显式类型: 禁止使用,必须显式声明类型
var - 空值安全: 使用OrNull后缀明确标记可空类型
- 断言验证: 所有假设都使用Debug.Assert
- 边界验证: 仅在边界处验证外部数据
- 使用init: 优先使用C# 9.0的private init(仅.NET 5+可用,Unity不支持)
- 禁止表情符号: 禁止在代码示例及文档中使用表情符号,使用文本标签([WRONG]、[CORRECT]、[CAUTION])