设计模式不仅仅是配方;它们是我们组织思维、扩展想法并使代码面向未来的方式。但随着框架的演进,并非所有模式都能保持其优势。
随着 .NET 10 的发布和 C# 12 的成熟,该平台变得更智能、更精简、更具表现力。许多我们过去需要手动处理的问题——如配置、日志记录、端点组合和异步消息传递——现在框架本身已内置了原生支持。这种转变带来了一代新的模式:这些模式不是由限制塑造,而是由机遇塑造。它们使你的代码更易于测试、重构更安全、阅读更清晰。
1. 极简API管道模式 (Minimal API Pipeline Pattern) 模式定义 一种将相关的 HTTP 端点组织到具有共享过滤器、设置和文档元数据的逻辑组中的方法。它用简洁、函数式的声明取代了控制器。
在 .NET 10 中的适用场景 极简API允许你使用委托定义路由,而路由组(Route Groups)提供了模块化和集中管理关注点的能力。
代码示例 (C#)
var users = app.MapGroup("/users")
.WithTags("Users")
.WithOpenApi();
users.MapGet("/", GetAllUsers);
users.MapPost("/", CreateUser)
.RequireAuthorization()
.WithValidator<CreateUserRequest>();
这为你提供了分组路由、共享行为和更好的 OpenAPI 文档——比传统的 MVC 更少的繁文缛节(ceremony)。
2. 选项模式(Options Pattern)与源生成(Source Generation) 模式定义 一种将应用程序配置绑定到强类型对象的结构化方法,具有编译时验证和 IntelliSense 支持。
在 .NET 10 中的适用场景 使用源生成器(source generators),.NET 可以自动绑定、验证和注册配置模型——不再需要脆弱的手动映射。
代码示例 (C#)
[OptionsBuilder("MySettings")]
[OptionsValidator]
internal partial class MySettings
{
public required string ApiKey { get; init; }
public int Timeout { get; set; } = 30;
}
// DI 注册
builder.Services.AddOptions<MySettings>()
.BindConfiguration()
.Validate();
安全、简洁且由编译器辅助的配置处理。
3. 命名服务策略模式 (Strategy Pattern with Named Services)
模式定义
一种抽象一系列算法或行为并在运行时选择其一的方法——无需 if
语句或工厂类。
在 .NET 10 中的适用场景 命名的依赖注入(DI)注册允许你使用简单的键(Key)来解析实现。
代码示例 (C#)
public interface IPaymentProcessor
{
Task ProcessAsync(Order order);
}
// 注册多个实现
builder.Services.AddTransient<IPaymentProcessor, StripeProcessor>("Stripe");
builder.Services.AddTransient<IPaymentProcessor, PayPalProcessor>("PayPal");
public class CheckoutService
{
private readonly Func<string, IPaymentProcessor> _resolve;
public CheckoutService(Func<string, IPaymentProcessor> resolve) =>
_resolve = resolve;
public Task CheckoutAsync(Order order, string provider) =>
_resolve(provider).ProcessAsync(order);
}
逻辑清晰分离,易于交换,完全可测试。
4. 基于通道(Channel)的通知模式 (Channel-Based Notification Pattern) 模式定义 一种使用异步安全队列在内存中发布事件或消息的方法——非常适合“即发即弃”(fire-and-forget)或后台处理。
在 .NET 10 中的适用场景
Channel<T>
允许你异步流式传输消息,并提供自然的背压(back-pressure)机制。
代码示例 (C#)
var channel = Channel.CreateUnbounded<UserEvent>();
// 生产者 (Producer)
await channel.Writer.WriteAsync(new UserEvent("SignedIn"));
// 消费者 (Consumer)
await foreach (var evt in channel.Reader.ReadAllAsync())
await HandleAsync(evt);
对于本地事件处理、后台作业或推送式架构非常有效。
5. MediatR 管道行为模式 (MediatR Pipeline Behavior) 模式定义 一种在命令或查询处理程序周围应用可重用行为(如验证、日志记录、重试)的模式。
在 .NET 10 中的适用场景 MediatR 与极简API自然契合,并且对 DI 友好。行为(Behaviors)促进了清晰的分离。
代码示例 (C#)
public class LoggingBehavior<TRequest, TResponse>
: IPipelineBehavior<TRequest, TResponse>
{
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken ct)
{
LogRequest(request);
return await next();
}
}
附加一次行为——即可将其应用于所有处理程序。
6. 记录类型(Records)与扩展方法(Extension Methods)的函数式组合 (Functional Composition) 模式定义 将逻辑建模为应用于不可变数据记录的小型纯函数——就像函数管道(function pipelines)。
在 .NET 10 中的适用场景 记录类型(Records)和扩展方法(Extension Methods)完美协作,可以清晰地表达转换管道。
代码示例 (C#)
public record Customer(string Name, decimal Balance);
public static class CustomerExtensions
{
public static Customer ApplyDiscount(this Customer c) =>
c with { Balance = c.Balance * 0.9M };
public static Customer AddLoyalty(this Customer c, int points) => c;
}
// 使用
var updated = customer
.ApplyDiscount()
.AddLoyalty(100);
无共享状态,只有纯粹的逻辑。易于测试、重用和组合。
7. 结构化日志(Structured Logging) + OpenTelemetry 的可观测性模式 (Observability) 模式定义 一种用于生成机器可读的日志和追踪(traces)以诊断生产问题的模式。
在 .NET 10 中的适用场景 源生成器创建了优化的结构化日志消息,并且 OpenTelemetry 直接集成到平台中。
代码示例 (C#)
[LoggerMessage(EventId = 200, Level = LogLevel.Information,
Message = "User {UserId} logged in from {IpAddress}")]
public static partial void UserLoggedIn(ILogger logger, string userId, string ip);
// 追踪 (Tracing) 设置
builder.Services.AddOpenTelemetryTracing(b =>
b.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddSource("MyApp"));
更好的诊断能力,减少开销,且无需混乱的字符串插值。
8. 端点过滤器模式 (Endpoint Filter Pattern) 模式定义 一种附加到极简API路由的内联过滤器,允许你拦截和修改请求/响应行为。
在 .NET 10 中的适用场景 过滤器消除了需要中间件(middleware)或基类来处理每个端点逻辑的需求。
代码示例 (C#)
app.MapPost("/orders", HandleOrder)
.AddEndpointFilter(async (context, next) =>
{
var request = context.GetArgument<OrderRequest>(0);
if (!IsValid(request)) return Results.BadRequest();
return await next(context); // 继续执行
});
非常适合验证、授权或塑造响应。
9. 结合路由组(Route Groups)的功能开关模式 (Feature Flag Pattern) 模式定义 根据配置、环境或用户声明在运行时启用或禁用功能——无需在服务内部编写分支逻辑。
在 .NET 10 中的适用场景 路由组(Route Groups)和策略(policies)让你能够清晰地隔离功能逻辑。
代码示例 (C#)
var beta = app.MapGroup("/beta")
.RequireAuthorization("BetaTester");
beta.MapGet("/search", NewSearchHandler);
你可以将实验性功能分组,而不会使现有的处理程序变得杂乱。
设计模式不仅仅是关于代码——它们关乎清晰度、意图和持久性。在 .NET 10 中,清晰度胜出。
这九种模式并非理论空谈——它们反映了 .NET 自身的演进方向。通过拥抱极简API、结构化日志记录、异步组合和更智能的配置模型,我们不再与框架对抗,而是开始与之和谐共处。结果如何?更少的开销、更快的上手速度、更好的可测试性,以及几乎可以自我文档化的代码。
你不必在一夜之间重构所有代码。选择一个模式。在功能分支中尝试一下。看看它如何简化你的思路。然后让这种势头继续前进。现代的 .NET 并不要求你构建更多——它要求你构建得更智能。这些模式就是你的起点。剩下的,只是编写整洁的代码(clean code)。