mcpField
M
modern-csharp

modern-csharp

github.com/codewithmukesh开发7913.0k 次安装12 周前更新
代码仓库

关于 modern-csharp

面向使用 C# 的开发者,提供 C# 14 和 .NET 10 的现代语言特性参考与实践建议。内容涵盖可读性、值类型、不可变性及常见反模式。

主要功能

  1. 01介绍 C# 14 语言特性
  2. 02展示集合表达式与模式匹配
  3. 03说明 field 关键字和扩展成员
  4. 04强调值类型与不可变性
  5. 05列举反模式及替代写法

适用场景

  1. 01更新 C# 项目的编码习惯
  2. 02为 DTO 和值对象选择类型
  3. 03减少字符串切片的分配
  4. 04改进属性验证与延迟初始化

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/codewithmukesh/dotnet-claude-kit --skill modern-csharp

安装后在 Claude Code 中输入/modern-csharp确认已加载。

详细介绍

现代 C#(C# 14 / .NET 10)

核心原则

  1. 使用最新的稳定功能 — 目标版本为 C# 14。优先使用语言级构造,而不是通过库变通实现。
  2. 可读性优先于巧妙 — 在适当情况下,模式匹配和表达式体成员可以提升可读性;深层嵌套的模式则不行。
  3. 尽可能使用值类型 — 优先使用 record struct、Span<T> 和栈分配,以减少 GC 压力。
  4. 默认保持不可变 — 使用 record、readonly、init 和 required,让非法状态无法表示。

模式

常用功能速查
功能用途示例
主构造函数DI 注入,消除字段赋值public class OrderService(IOrderRepo repo, TimeProvider clock) { }
集合表达式所有集合类型均可使用 [] + 展开List<string> names = ["Alice", "Bob"]; / int[] all = [..a, ..b, 99];
RecordsDTO、值对象、不可变数据public record CreateOrderRequest(string CustomerId, List<OrderItem> Items);
readonly record struct小型栈分配值类型public readonly record struct Money(decimal Amount, string Currency);
模式匹配Switch 表达式、列表/属性模式order switch { { Total: > 1000 } => "Premium", _ => "Standard" };
列表模式解构数组/列表items switch { [] => "Empty", [var x] => $"One: {x}", [var f, .., var l] => $"{f}..{l}" };
Span<T>零分配切片ReadOnlySpan<char> trimmed = input.Trim(); int.TryParse(trimmed[4..], out id);
原始字符串字面量多行 SQL、JSON、XMLvar sql = """ SELECT ... """; / 插值形式:$$""" {"id": "{{id}}"} """;
required 成员强制初始化public required string ConnectionString { get; init; }
is 模式 + 提取空值/类型/属性检查if (result is { IsSuccess: true, Value: var order }) { ... }
field 关键字(C# 14)

在属性访问器中访问自动生成的后备字段,无需手动声明。

// 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));
    }
}
使用 field 延迟初始化
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 */;
}
使用 field 通知更改
// 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)));
        }
    }
}
扩展成员(C# 14)

C# 14 在静态类中新增了 extension 块。与传统扩展方法不同,它支持扩展属性和静态扩展成员——整个块只需声明一次接收者。

// 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) { /* ... */ }

传统的 this 参数扩展方法仍然有效,也可以共存——需要属性或针对同一接收者定义多个成员时,使用扩展块。

反模式

有现代替代方案时,不要使用过时模式
// 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);
不要过度使用模式匹配
// 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")
类型不明显时,不要使用 var
// 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>();

决策指南

场景建议
DTO / API 契约record(引用类型)
小型值对象(2-3 个字段)readonly record struct
使用 DI 的服务主构造函数
创建集合集合表达式 []
带验证的属性field 关键字
多行字符串(SQL、JSON)原始字符串字面量 """
切片字符串/数组Span<T>
类型检查 + 提取使用 is / switch 进行模式匹配
强制初始化required 修饰符
为外部类型添加方法扩展成员

评论

支持 Markdown