通常情况下,出于多种原因,我不会说我喜欢写关于预览功能的文章。我的大多数帖子旨在帮助人们解决他们可能遇到的问题,而不是找个肥皂盒或打广告。但是我认为我应该介绍这个 .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)的更多相关文章

  1. struts2学习笔记--拦截器(Interceptor)和登录权限验证Demo

    理解 Interceptor拦截器类似于我们学过的过滤器,是可以在action执行前后执行的代码.是我们做web开发是经常使用的技术,比如权限控制,日志.我们也可以把多个interceptor连在一起 ...

  2. struts2拦截器interceptor的三种配置方法

    1.struts2拦截器interceptor的三种配置方法 方法1. 普通配置法 <struts> <package name="struts2" extend ...

  3. SSM-SpringMVC-33:SpringMVC中拦截器Interceptor讲解

     ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 拦截器Interceptor: 对处理方法进行双向的拦截,可以对其做日志记录等 我选择的是实现Handler ...

  4. 过滤器(Filter)和拦截器(Interceptor)

    过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序.它依赖于servlet容器,在实现上,基于函数回调,它可以对几乎所有请求 ...

  5. 二十五、过滤器Filter,监听器Listener,拦截器Interceptor的区别

    1.Servlet:运行在服务器上可以动态生成web页面.servlet的声明周期从被装入到web服务器内存,到服务器关闭结束.一般启动web服务器时会加载servelt的实例进行装入,然后初始化工作 ...

  6. Flume 拦截器(interceptor)详解

    flume 拦截器(interceptor)1.flume拦截器介绍拦截器是简单的插件式组件,设置在source和channel之间.source接收到的事件event,在写入channel之前,拦截 ...

  7. struts2拦截器interceptor的配置方法及使用

    转: struts2拦截器interceptor的配置方法及使用 (2015-11-09 10:22:28) 转载▼ 标签: it 365 分类: Struts2  NormalText Code  ...

  8. Kafka producer拦截器(interceptor)

    Producer拦截器(interceptor)是个相当新的功能,它和consumer端interceptor是在Kafka 0.10版本被引入的,主要用于实现clients端的定制化控制逻辑. 对于 ...

  9. Flume-NG源码阅读之SourceRunner,及选择器selector和拦截器interceptor的执行

    在AbstractConfigurationProvider类中loadSources方法会将所有的source进行封装成SourceRunner放到了Map<String, SourceRun ...

  10. JavaWeb—拦截器Interceptor

    1.概念 java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取A ...

随机推荐

  1. 使用 React Three Fiber 和 GSAP 实现 WebGL 轮播动画

    参考:Building a WebGL Carousel with React Three Fiber and GSAP 在线 demo github 源码 效果来源于由 Eum Ray 创建的网站 ...

  2. django的部署在centos

    虚拟环境 #virtualenv是一个创建独立python环境的工具 sudo pip install virtualenv #virtualenvwrapper将所有的虚拟环境统一管理,留意安装路径 ...

  3. 关于int**在malloc为二维数组分配空间时候的作用见解

    关于int**在用malloc函数为二维数组分配空间时候 int**   二级指针类型 二维数组的数组名为行指针,写成  arr  =(char**)malloc(n*sizeof(char))时,a ...

  4. 行行AI人才直播第5期:系列课-AI理解及ChatGPT从基础到高级应用

    当前,人工智能是全世界研究的重点对象,也是人们茶余饭后讨论的经典话题.自从 OpenAI 发布 ChatGPT-4 之后,似乎无论是在工作.娱乐.甚至是日常生活中,我们都能感受到AI带来的便利和改变. ...

  5. Js中几种循环的使用

    在JavaScript中有五种常用的循环,现在来分别介绍一下五种循环的用法. 1.while 当满足条件时进入循环,进入循环后,当条件不满足时,跳出循环.while语句的一般表达式为:while(表达 ...

  6. ZEGO全新语音聊天室方案,2小时复刻 Clubhouse

    真的火了! 新晋带货王马斯克在 Clubhouse"开房"之后,直接让 Clubhouse 爆火出圈,据说,Clubhouse 平台邀请码现在在ebay上已经卖到了快200刀一个. ...

  7. 云储存选择做Hexo博客图床(腾讯云、七牛云、网易云)

    前言 博客里需要添加很多图片作为内容的补充,但是把图片放在本地博客文件夹里,上传到网上后,加载这些图片就是一个很大的问题,他们会拖累网页加载的速度,所以建议把图片放图床里,通过外链来访问和加载这些图片 ...

  8. 2023-07-17:给定一个数组arr,长度为n, 再给定一个数字k,表示一定要将arr划分成k个集合, 每个数字只能进一个集合。 返回每个集合内部的平均值都累加起来最小的值。 平均值向下取整。 1

    2023-07-17:给定一个数组arr,长度为n, 再给定一个数字k,表示一定要将arr划分成k个集合, 每个数字只能进一个集合. 返回每个集合内部的平均值都累加起来最小的值. 平均值向下取整. 1 ...

  9. Llama2 论文中译版——开放式基础和微调聊天模型

    Llama 2:开放式基础和微调聊天模型 写在前头 因为最近一直在使用 LLM 工具,所以在学习 Llama 2:开放式基础和微调聊天模型 这篇论文的期间,顺手将内容翻译了过来. 整片译文是由 Cha ...

  10. chrome pre 自动换行

    问题引出 当我想要使用chrome的打印功能生成一份关于md的pdf版本的时候发现有的代码块没有自动换行,生成的PDF没有自动换行,导致部分信息无法阅读 处理方式 把有自动换行的部分处理一下,在md文 ...