【译】.NET 8 拦截器(interceptor)
通常情况下,出于多种原因,我不会说我喜欢写关于预览功能的文章。我的大多数帖子旨在帮助人们解决他们可能遇到的问题,而不是找个肥皂盒或打广告。但是我认为我应该介绍这个 .NET 预览特性,因为它是我在 .NET 生态系统中渴望已久的东西(猴子补丁,monkey patching,在运行时动态修改模块、类或函数,通常是添加功能或修正缺陷,猴子补丁在代码运行时内存中发挥作用,不会修改源码,因此只对当前运行的程序实例有效;因为猴子补丁破坏了封装,而且容易导致程序与补丁代码的实现细节紧密耦合,所以被视为临时的变通方案,不是集成代码的推荐方式)的姊妹主题。如果你不熟悉这个话题,我建议你阅读我关于猴子打补丁的帖子。一般来说,猴子补丁允许你用一个实现代替另一个实现,你知道吗,. NET 8引入了拦截器的概念。
顾名思义,拦截器允许开发人员针对特定的方法调用,用新的实现拦截它们。拦截器有几个目的和重要的区别,我们将在这篇文章中讨论。让我们开始吧。
拦截器是什么?
在 .NET 8预览版6中,SDK 引入了额外的功能来“拦截”代码库中的任何方法调用。“interceptor(拦截器)”这个词很清楚地说明了这个新功能的目的。它只是有意地替换方法,而不是全局地替换方法实现。这种方法意味着,作为开发人员,您必须系统地使用拦截器。
. NET 团队使用拦截器将以前依赖于反射的基础架构代码重写为特定于应用程序的编译时版本。拦截器有望减少程序的启动时间和提高效率。. NET 团队设计了拦截器来与源代码生成器(source generator)一起工作,因为源代码生成器可以处理抽象语法树和代码文件以实现目标方法调用。虽然您可以手动编写拦截器调用,但这在实际应用程序中是不切实际的。
让我们开始设置您的项目以使用拦截器。
入门
拦截器是 .NET 8预览版6的一个特性,所以你需要匹配其 SDK 版本或更高版本才能使用它。首先创建一个新的控制台应用程序,或者任何 .NET 应用程序。
接下来,在 .csproj 中,必须添加以下 PropertyGroup 元素。
<PropertyGroup>
<Features>InterceptorsPreview</Features>
</PropertyGroup>
还要确保将 LangVersion 元素设置为预览以访问该特性。
<PropertyGroup>
<LangVersion>preview</LangVersion>
</PropertyGroup>
接下来,将以下属性定义添加到项目中。
namespace System.Runtime.CompilerServices; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int character)
{
}
}
是的,这个属性不是 BCL 的一部分是很奇怪的,但由于这是一个预览特性,我想 .NET 团队不想在以后的 API 更改中污染 .NET 框架。
您将注意到该属性有三个参数:filePath、line 和 character。您还会注意到,这些值没有在任何地方赋值,您是正确的。该属性是编译器将在编译时读取的标记,因此设置运行时使用的值是没有意义的。
现在,让我们拦截一些代码。将以下内容添加到 Program.cs 文件中。注意,行号和间距非常重要。如果重新格式化代码,这个解决方案可能会失效。还要确保将文件路径更改为 Program.cs 文件的绝对路径。
using System.Runtime.CompilerServices; C.M(); // What the Fudge?!
C.M(); // Original class C
{
public static void M() => Console.WriteLine("Original");
} // generated
class D
{
[InterceptsLocation("/Users/khalidabuhakmeh/RiderProjects/ConsoleApp12/ConsoleApp12/Program.cs",
line: 3, character: 3)]
public static void M() => Console.WriteLine("What the Fudge?!");
}
运行上面的应用程序,您将看到最奇怪的事情。同一个方法调用的两个不同输出!搞什么鬼?

如何做到的?编译后的代码是什么样子的?我们可以使用 JetBrains Rider 的 IL Viewer 看到发生了什么。
// Decompiled with JetBrains decompiler
// Type: Program
// Assembly: ConsoleApp12, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 09D7E1E0-5709-4A62-884A-AB84DAA1E08C
// Assembly location: /Users/khalidabuhakmeh/RiderProjects/ConsoleApp12/ConsoleApp12/bin/Debug/net8.0/ConsoleApp12.dll
// Local variable names from /users/khalidabuhakmeh/riderprojects/consoleapp12/consoleapp12/bin/debug/net8.0/consoleapp12.pdb
// Compiler-generated code is shown using System.Runtime.CompilerServices; [CompilerGenerated]
internal class Program
{
private static void <Main>$(string[] args)
{
D.M();
C.M();
} public Program()
{
base..ctor();
}
}
现在可以看到,编译器用我们的拦截实现替换了第一个方法调用。哇!
在这种令人眼花缭乱的感觉褪去之后,你可能会认为这是不切实际的。谁有时间硬编码文件的完整路径、计算行数和列数呢?正如前面提到的,这就是源代码生成器的用武之地。
虽然在处理语法树时我不会在这里演示它,但是您确实可以访问如 FilePath 之类的信息,并且每个 CSharpSyntaxNode 都有一个 GetLocation 方法,该方法使您可以访问代码文件中的行号和位置。如果您已经精通编写源代码生成器,那么您已经可以获得这些信息。
结论
这个特性是针对 .NET 社区中特定的一群人,特别是那些编写和维护源代码生成器的人。在这个小群体中,您可能会有框架作者希望从 .NET 中挤出最后一点性能。正如您所看到的,拦截器只能更改特定的实现,而不能全局地针对方法。如果使用源代码生成器对所有方法进行拦截,则必须为每个位置生成一个拦截调用。生成大量自定义代码可能会对编译资产的大小产生不利影响,因此要注意使用此特性。另外,您可以考虑完全避免这个功能。拦截器仍处于预览阶段,其主要目的是帮助 .NET 作者改进 ASP .NET Core 和 .NET SDK 中的其他框架。不管怎样,在下次调试 .NET 8应用程序时,了解这个特性是有好处的,因为你认为你调用的方法可能不是你实际调用的方法。
我希望你喜欢这篇博文,并一如既往地感谢你阅读并与朋友和同事分享我的博文。
原文链接:https://khalidabuhakmeh.com/dotnet-8-interceptors

【译】.NET 8 拦截器(interceptor)的更多相关文章
- struts2学习笔记--拦截器(Interceptor)和登录权限验证Demo
理解 Interceptor拦截器类似于我们学过的过滤器,是可以在action执行前后执行的代码.是我们做web开发是经常使用的技术,比如权限控制,日志.我们也可以把多个interceptor连在一起 ...
- struts2拦截器interceptor的三种配置方法
1.struts2拦截器interceptor的三种配置方法 方法1. 普通配置法 <struts> <package name="struts2" extend ...
- SSM-SpringMVC-33:SpringMVC中拦截器Interceptor讲解
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 拦截器Interceptor: 对处理方法进行双向的拦截,可以对其做日志记录等 我选择的是实现Handler ...
- 过滤器(Filter)和拦截器(Interceptor)
过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序.它依赖于servlet容器,在实现上,基于函数回调,它可以对几乎所有请求 ...
- 二十五、过滤器Filter,监听器Listener,拦截器Interceptor的区别
1.Servlet:运行在服务器上可以动态生成web页面.servlet的声明周期从被装入到web服务器内存,到服务器关闭结束.一般启动web服务器时会加载servelt的实例进行装入,然后初始化工作 ...
- Flume 拦截器(interceptor)详解
flume 拦截器(interceptor)1.flume拦截器介绍拦截器是简单的插件式组件,设置在source和channel之间.source接收到的事件event,在写入channel之前,拦截 ...
- struts2拦截器interceptor的配置方法及使用
转: struts2拦截器interceptor的配置方法及使用 (2015-11-09 10:22:28) 转载▼ 标签: it 365 分类: Struts2 NormalText Code ...
- Kafka producer拦截器(interceptor)
Producer拦截器(interceptor)是个相当新的功能,它和consumer端interceptor是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制逻辑. 对于 ...
- Flume-NG源码阅读之SourceRunner,及选择器selector和拦截器interceptor的执行
在AbstractConfigurationProvider类中loadSources方法会将所有的source进行封装成SourceRunner放到了Map<String, SourceRun ...
- JavaWeb—拦截器Interceptor
1.概念 java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取A ...
随机推荐
- < Python全景系列-5 > 解锁Python并发编程:多线程和多进程的神秘面纱揭晓
欢迎来到我们的系列博客<Python全景系列>!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法.无论你是编程新手,还是有一 ...
- linux DNS域名解析
目录 一.DNS概念 二.域名格式类型 三.查询类型 四.解析类型 五.配置DNS 六.dns解析实验 1.配置正向解析 2.反向解析 3.主从解析 一.DNS概念 概念:域名和IP地址的相互映射的分 ...
- GitHub上SSH keys和Deploy keys的区别
平时安装一个git然后去GitHub进行SSH keys 配置最后就开始使用,然后换一台电脑再使用$ ssh-keygen -t rsa -C "your email"生成一个ss ...
- java开发学习框架
Java基础 1.1. Java简介与安装 1.2. Java基本语法 1.3. 数据类型与变量 1.4. 运算符与表达式 1.5. 流程控制(分支与循环) 1.6. 数组 面向对象编程 2.1. 类 ...
- 百度飞桨(PaddlePaddle) - PP-OCRv3 文字检测识别系统 预测部署简介与总览
百度飞桨(PaddlePaddle) - PP-OCRv3 文字检测识别系统 预测部署简介与总览 百度飞桨(PaddlePaddle) - PP-OCRv3 文字检测识别系统 Paddle Infer ...
- 通过命令行创建ACFS文件系统
其实使用asmca图形创建ACFS文件系统既简单又不容易出错,但是考虑到某些客户场景不允许我们调取图形,所以本文演示下通过命令行创建ACFS文件系统的步骤. 可以通过MOS搜索到下面这篇文档: ASM ...
- 发现了阿里云 APP 的一个小 BUG
由于微信不允许外部链接,你需要点击文章尾部左下角的 "阅读原文",才能访问文中链接. 前几天在华为手机上使用阿里云 APP,从 oss bucket 中下载了一张图片,想要通过微信 ...
- 800名科学家Nature联名发文主张废除p值!
每年,全球有数百万学生修读统计学课程.随着世界上的数据量越来越大,统计学已成为越来越受欢迎的话题.如果大多数学生都从这门课中记住一点,那可能就是"统计显著性"和"p 值& ...
- GPT3的内部结构:基于自回归、注意力机制等技术的语言处理框架
目录 1. 引言 2. 技术原理及概念 3. 实现步骤与流程 4. 应用示例与代码实现讲解 6. 结论与展望 7. 附录:常见问题与解答 GPT-3 是当前最为先进的自然语言处理框架之一,由 Open ...
- k8s驱逐篇(6)-kube-controller-manager驱逐-NodeLifecycleController源码分析
概述 k8s v1.16版本中NodeController已经分为了NodeIpamController与NodeLifecycleController,本文主要介绍NodeLifecycleCont ...