0

0

c# C# 12 的 Interceptors 和并发代码的AOP实现

月夜之吻

月夜之吻

发布时间:2026-01-21 12:13:09

|

327人浏览过

|

来源于php中文网

原创

<p>C# 12 Interceptors 无法用于并发 AOP,因其仅支持编译期重写同步方法,不支持 async 方法及状态机;替代方案包括 Source Generators 手动插桩、Castle 代理(有限制)或组合式扩展方法封装。</p>

c# c# 12 的 interceptors 和并发代码的aop实现

Interceptors 在 C# 12 中不能用于并发 AOP

C# 12 的 Interceptors 是编译期重写机制,不是运行时拦截,它无法作用于已编译的异步方法、async 方法体、或任何涉及 Task/ValueTask 状态机的调用。你写一个 [InterceptsLocation(...)] 尝试拦截 DoWorkAsync(),编译器会直接报错:Interceptors cannot intercept async methods

这意味着:你不能靠 Interceptors 实现「在 await 前后自动加锁/记录耗时/注入取消检查」这类典型并发 AOP 场景。

  • Interceptor 只能重写普通同步方法、属性 getter/setter、构造函数调用点(且必须是源码可见、同一编译单元)
  • 所有 await 表达式都由编译器展开为状态机类型(如 DoWorkAsync>d__5),Interceptor 无法插入其中
  • 即使你拦截了调用方的同步入口(比如 StartProcessing()),也无法穿透到其内部的 await File.ReadAsync()

并发 AOP 的可行替代方案:Source Generators + 手动 await 插桩

如果你真需要对异步方法做横切逻辑(比如自动超时包装、上下文传播、重试策略),目前最可控的方式是用 Source Generator 在编译期生成带包装逻辑的新方法,并要求开发者显式调用生成的方法(而非原方法)。

例如:你定义一个 [AutoTimeout(3000)] 特性,Generator 检测到标记了该特性的 async Task<int> GetData(),就生成一个 GetData_WithTimeout()

public async Task<int> GetData_WithTimeout()
{
    using var cts = new CancellationTokenSource(3000);
    try
    {
        return await GetData().WaitAsync(cts.Token);
    }
    catch (OperationCanceledException) when (cts.IsCancellationRequested)
    {
        throw new TimeoutException("GetData timed out after 3000ms");
    }
}
  • 必须显式调用 GetData_WithTimeout(),原方法不变 —— 这是关键约束,没有“透明拦截”
  • Generator 无法修改已有 async 方法体,只能新增;也不能自动替换调用点(那属于 Roslyn Analyzer + CodeFix 范畴)
  • 若需支持 ValueTask 或流式 await(如 IAsyncEnumerable),需额外判断返回类型并生成对应逻辑

运行时方案:AOP 框架仍依赖代理(如 Castle DynamicProxy)但有严重限制

在 .NET 6+ 上,Castle.DynamicProxy 仍可对实现接口的类做异步方法代理,但它只拦截「接口调用」,且所有被代理的 async 方法必须声明为 Task(不能是 ValueTask),否则代理会丢失 await 上下文或引发 InvalidOperationException

Chromox
Chromox

Chromox是一款领先的AI在线生成平台,专为喜欢AI生成技术的爱好者制作的多种图像、视频生成方式的内容型工具平台。

下载

典型错误现象:System.InvalidOperationException: Synchronous operations are not permitted. Call WriteAsync or set AllowSynchronousIO to true. —— 这往往是因为代理层同步等待了 async 方法,破坏了 ASP.NET Core 的 IO 上下文约束。

  • 仅适用于 public 接口方法;sealed 类、private/protected async 方法完全不可代理
  • 每次 await 都经过代理调度器,性能开销明显(尤其高频小任务)
  • .NET 8+ 中 DispatchProxy 不支持 async 方法,RealProxy 已废弃,实际只剩 Castle 可用但维护停滞

真正轻量且推荐的做法:组合式手动封装 + 命名约定

放弃“全自动 AOP”,改用显式但低侵入的封装模式。例如定义一组扩展方法,把横切逻辑收敛成可复用的组合子:

public static class ConcurrencyExtensions
{
    public static async Task<T> WithTimeout<T>(this Func<Task<T>> operation, int milliseconds, string opName = "")
    {
        using var cts = new CancellationTokenSource(milliseconds);
        try
        {
            return await operation().WaitAsync(cts.Token);
        }
        catch (OperationCanceledException) when (cts.IsCancellationRequested)
        {
            throw new TimeoutException($"Operation '{opName}' timed out");
        }
    }
}

然后这样用:

var result = await (() => repository.FetchDataAsync()).WithTimeout(5000, "FetchData");
  • 无反射、无代理、无生成代码,纯委托 + async/await 组合,性能接近手写
  • 调用点清晰可见,调试时堆干净,不会出现“Interceptor_xxx”或“GeneratedProxy”等干扰帧
  • 配合 IDE 的 Live Template 或 ReSharper 宏,可以一键补全 .WithTimeout(...),效率不输 AOP

真正的难点不在语法或工具,而在于:你是否愿意让并发控制逻辑暴露在调用端 —— 这其实是更健康的职责划分。强行隐藏,反而会让 timeout、retry、cancellation 的语义变得模糊且难以追踪。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1030

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

612

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

334

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

235

2025.08.29

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1926

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

656

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2395

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

47

2026.01.19

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 6万人学习

ASP 教程
ASP 教程

共34课时 | 5.8万人学习

Vue3.x 工具篇--十天技能课堂
Vue3.x 工具篇--十天技能课堂

共26课时 | 1.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号