C# 拦截器Interceptors方法 C# 12的拦截器是什么(预览功能)

来源:这里教程网 时间:2026-02-21 17:42:20 作者:

Interceptors 是 C# 12 的预览功能,不是运行时拦截器

它不是类似

IAuthorizationFilter
IDispatchProxy
那种在程序运行时动态介入调用的机制。C# 12 的
Interceptors
是编译期重写技术:编译器识别标记了
[InterceptsLocation]
的方法,在生成 IL 时,把对目标方法的调用直接替换成对拦截器方法的调用——原方法甚至不会出现在最终输出的程序集中。

这意味着:

它不依赖反射、代理或运行时织入,无性能开销 仅适用于
internal
private
方法(public 方法调用可能跨程序集,无法安全重写)
必须启用预览功能:
<langversion>12.0</langversion>
+
<enablepreviewfeatures>true</enablepreviewfeatures>
目前仅支持源代码在同一项目中,且拦截器和被拦截方法都必须在同一个编译单元内

怎么写一个合法的拦截器方法

拦截器不是任意方法,必须严格满足签名和属性约束,否则编译失败(错误如

CS8954
CS8955
):

返回类型必须与被拦截方法完全一致(含
void
Task
、泛型等)
参数列表必须与被拦截方法**逐个位置、逐个类型匹配**(不能多参、少参、类型隐式转换也不行) 必须标注
[InterceptsLocation(...)]
,参数是字符串字面量,格式为
"{文件路径}:{行号}:{列号}"
,指向被拦截方法的声明位置
必须是
static
internal
(不能是
public
private

示例:

[InterceptsLocation("Program.cs:12:5")]
internal static string GetGreeting() => "Hello from interceptor!";

对应被拦截的方法需写在

Program.cs
第 12 行第 5 列(通常是方法名起始位置):

internal static string GetGreeting() => "Hello world"; // 这行会被完全跳过

常见失败场景:为什么拦截没生效

拦截器“静默失效”很常见,根本原因是编译器拒绝应用重写。典型原因包括:

[InterceptsLocation]
路径错误:文件名大小写不符、路径是相对/绝对混淆、行号列号偏移(比如注释占行、IDE 显示行号 vs 实际行号)
被拦截方法不是
internal
private
(例如
public
成员被其他项目引用)
拦截器方法和被拦截方法不在同一源文件、或分属不同
partial
类但未被编译器视为同一逻辑单元
启用了增量编译但缓存未刷新,可尝试
dotnet clean
后重试
使用了不支持该特性的 SDK 版本(需 .NET 8 SDK RC2+,且项目 SDK 为
Microsoft.NET.Sdk

它不适合替代 AOP 或日志框架

Interceptors 不是

Castle.DynamicProxy
AspectCore
Microsoft.Extensions.DependencyInjection
中的拦截扩展。它没有上下文、无法访问调用栈、不能处理异常后逻辑、也不支持条件拦截(比如只拦截特定参数值)。它的定位非常窄:用于极底层、确定性替换,比如:

在测试中静态替换某个配置读取方法,避免启动完整 DI 容器 在发布构建中将调试日志调用直接替换为空实现 为特定平台 API 提供编译期 fallback 实现(如 Windows-only 方法在 Linux 下替换为 stub)

一旦你想到“我需要在方法执行前后做点什么”,那它就不是合适工具——这时候该用

Source Generators
DiagnosticAnalyzer
,或者老老实实写装饰器。

相关推荐