modern-csharp
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseModern C# (C# 14 / .NET 10)
现代C#(C# 14 / .NET 10)
Core Principles
核心原则
- Use the newest stable features — C# 14 is the target. Prefer language-level constructs over library workarounds.
- Readability over cleverness — Pattern matching and expression-bodied members improve readability when used appropriately; deeply nested patterns do not.
- Value types where possible — Prefer ,
record struct, and stack allocation to reduce GC pressure.Span<T> - Immutability by default — Use ,
record,readonly, andinitto make illegal states unrepresentable.required
- 使用最新稳定特性 —— 目标为C# 14。优先使用语言级构造而非库的变通方案。
- 可读性优于技巧性 —— 模式匹配和表达式体成员在恰当使用时可提升可读性,但深度嵌套的模式则不然。
- 尽可能使用值类型 —— 优先选择、
record struct和栈分配以减少GC压力。Span<T> - 默认不可变 —— 使用、
record、readonly和init使非法状态无法被表示。required
Patterns
模式
Well-Known Features Quick Reference
常用特性速查
| Feature | Usage | Example |
|---|---|---|
| Primary constructors | DI injection, eliminate field assignments | |
| Collection expressions | | |
| Records | DTOs, value objects, immutable data | |
| Small stack-allocated value types | |
| Pattern matching | Switch expressions, list/property patterns | |
| List patterns | Deconstruct arrays/lists | |
| Zero-allocation slicing | |
| Raw string literals | Multi-line SQL, JSON, XML | |
| Enforce initialization | |
| Null/type/property check | |
| 特性(Feature) | 用法(Usage) | 示例(Example) |
|---|---|---|
| Primary constructors | 依赖注入(DI)、消除字段赋值 | |
| Collection expressions | 用 | |
| Records | 数据传输对象(DTO)、值对象、不可变数据 | |
| 小型栈分配值类型 | |
| Pattern matching | 开关表达式、列表/属性模式 | |
| List patterns | 解构数组/列表 | |
| 零分配切片 | |
| Raw string literals | 多行SQL、JSON、XML | |
| 强制初始化 | |
| 空值/类型/属性检查 | |
The field
Keyword (C# 14)
fieldfield
关键字(C# 14)
fieldAccess the auto-generated backing field in property accessors without declaring it manually.
csharp
// GOOD — field keyword for validation in auto-property
public class Product
{
public string Name
{
get => field;
set => field = value?.Trim() ?? throw new ArgumentNullException(nameof(value));
}
public decimal Price
{
get => field;
set => field = value >= 0 ? value : throw new ArgumentOutOfRangeException(nameof(value));
}
}在属性访问器中访问自动生成的后备字段,无需手动声明。
csharp
// GOOD — 使用field关键字实现自动属性验证
public class Product
{
public string Name
{
get => field;
set => field = value?.Trim() ?? throw new ArgumentNullException(nameof(value));
}
public decimal Price
{
get => field;
set => field = value >= 0 ? value : throw new ArgumentOutOfRangeException(nameof(value));
}
}Lazy Initialization with field
field使用field
实现延迟初始化
fieldcsharp
public class ProductCatalog
{
// Lazy-load on first access — no manual Lazy<T> or backing field
public IReadOnlyList<Product> Products
{
get => field ??= LoadProducts();
}
private static List<Product> LoadProducts() => /* expensive load */;
}csharp
public class ProductCatalog
{
// 首次访问时延迟加载 —— 无需手动使用Lazy<T>或后备字段
public IReadOnlyList<Product> Products
{
get => field ??= LoadProducts();
}
private static List<Product> LoadProducts() => /* 耗时加载逻辑 */;
}Change Notification with field
field使用field
实现变更通知
fieldcsharp
// INotifyPropertyChanged without manual backing fields
public class OrderViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public string CustomerName
{
get => field;
set
{
if (field == value) return;
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CustomerName)));
}
} = "";
public decimal Total
{
get => field;
set
{
if (field == value) return;
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Total)));
}
}
}csharp
// 无需手动后备字段的INotifyPropertyChanged实现
public class OrderViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public string CustomerName
{
get => field;
set
{
if (field == value) return;
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CustomerName)));
}
} = "";
public decimal Total
{
get => field;
set
{
if (field == value) return;
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Total)));
}
}
}Extension Members (C# 14)
扩展成员(C# 14)
C# 14 adds blocks inside static classes. Unlike classic extension methods, they support extension properties and static extension members — the receiver is declared once for the whole block.
extensioncsharp
// GOOD — extension block (shipped C# 14 syntax)
public static class OrderExtensions
{
extension(Order order)
{
public decimal TotalWithTax => order.Total * 1.2m;
public bool IsHighValue => order.Total > 1000m;
public string ToSummary() =>
$"Order #{order.Id}: {order.Total:C} ({order.Items.Count} items)";
}
// Static extension members use the type (no receiver instance)
extension(Order)
{
public static Order Empty => Order.Create("none", [], DateTimeOffset.MinValue);
}
}
// Callers see them as if declared on Order
if (order.IsHighValue) { /* ... */ }Classic -parameter extension methods still work and coexist — use extension blocks when you need properties or several members on the same receiver.
thisC# 14在静态类中新增了块。与传统扩展方法不同,它支持扩展属性和静态扩展成员——接收者为整个块声明一次。
extensioncsharp
// GOOD — 扩展块(C# 14正式语法)
public static class OrderExtensions
{
extension(Order order)
{
public decimal TotalWithTax => order.Total * 1.2m;
public bool IsHighValue => order.Total > 1000m;
public string ToSummary() =>
$"Order #{order.Id}: {order.Total:C} ({order.Items.Count} items)";
}
// 静态扩展成员使用类型(无需接收者实例)
extension(Order)
{
public static Order Empty => Order.Create("none", [], DateTimeOffset.MinValue);
}
}
// 调用者可像调用Order自身成员一样使用它们
if (order.IsHighValue) { /* ... */ }传统的带参数的扩展方法仍然有效并可共存——当需要为同一接收者添加多个成员或属性时,使用扩展块。
thisAnti-patterns
反模式
Don't Use Obsolete Patterns When Modern Alternatives Exist
当有现代替代方案时,不要使用过时模式
csharp
// BAD — manual backing field when field keyword works
private string _name;
public string Name
{
get => _name;
set => _name = value ?? throw new ArgumentNullException();
}
// BAD — old-style collection initialization
var list = new List<int>() { 1, 2, 3 };
// BAD — Tuple instead of record for domain types
(string Name, decimal Price) product = ("Widget", 9.99m);
// GOOD — record
public record Product(string Name, decimal Price);csharp
// BAD — 当field关键字可用时,仍手动声明后备字段
private string _name;
public string Name
{
get => _name;
set => _name = value ?? throw new ArgumentNullException();
}
// BAD — 旧式集合初始化方式
var list = new List<int>() { 1, 2, 3 };
// BAD — 领域类型使用Tuple而非record
(string Name, decimal Price) product = ("Widget", 9.99m);
// GOOD — 使用record
public record Product(string Name, decimal Price);Don't Over-pattern-match
不要过度使用模式匹配
csharp
// BAD — deeply nested pattern that's hard to read
if (order is { Customer: { Address: { Country: { Code: "US" } } } })
// GOOD — extract to a clear method or use sequential checks
if (order.Customer.Address.Country.Code == "US")csharp
// BAD — 深度嵌套的模式难以阅读
if (order is { Customer: { Address: { Country: { Code: "US" } } } })
// GOOD — 提取为清晰的方法或使用顺序检查
if (order.Customer.Address.Country.Code == "US")Don't Use var
When the Type Is Not Obvious
var当类型不明显时,不要使用var
varcsharp
// BAD — what type is this?
var result = Process(order);
// GOOD — explicit type when not obvious
Result<Order> result = Process(order);
// Also GOOD — var is fine when type is apparent
var orders = new List<Order>();csharp
// BAD — 无法明确此变量类型
var result = Process(order);
// GOOD — 类型不明确时使用显式类型
Result<Order> result = Process(order);
// 同样GOOD — 类型明显时使用var没问题
var orders = new List<Order>();Decision Guide
决策指南
| Scenario | Recommendation |
|---|---|
| DTO / API contract | |
| Small value object (2-3 fields) | |
| Service with DI | Primary constructor |
| Collection creation | Collection expression |
| Property with validation | |
| Multi-line string (SQL, JSON) | Raw string literal |
| Slicing strings/arrays | |
| Type checking + extraction | Pattern matching with |
| Enforced initialization | |
| Adding methods to external types | Extension members |
| 场景(Scenario) | 推荐方案(Recommendation) |
|---|---|
| DTO / API契约 | |
| 小型值对象(2-3个字段) | |
| 带依赖注入的服务 | Primary constructor |
| 集合创建 | 集合表达式 |
| 带验证的属性 | |
| 多行字符串(SQL、JSON) | 原始字符串字面量 |
| 字符串/数组切片 | |
| 类型检查 + 提取 | 使用 |
| 强制初始化 | |
| 为外部类型添加方法 | 扩展成员 |