通常情况下,出于多种原因,我不会说我喜欢写关于预览功能的文章。我的大多数帖子旨在帮助人们解决他们可能遇到的问题,而不是找个肥皂盒或打广告。但是我认为我应该介绍这个 .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. 《数据结构(C语言版)》严蔚敏代码实现———链表

    一.前言 哈喽,大家好~我是熊子q,我又来了! 他来了他来了,他带着代码过来了! 今天要分享的代码是链表!快快搬着小板凳! 二.代码 严奶奶的书中预定义了一些预定义常量和类型,大家可以 新建一个y.h ...

  2. [C#]插件编程框架 MAF 开发总结

    1. 什么是MAF和MEF? MEF和MEF微软官方介绍:https://learn.microsoft.com/zh-cn/dotnet/framework/mef/ MEF是轻量化的插件框架,MA ...

  3. Curl 中 关于PUT, POST, DELETE, UPDATE 的使用

    POST curl -H "Content-Type:application/json" -X POST --data '{"id":1, "text ...

  4. js如何操作video标签

    一.简介 在做web ui自动化时,遇到操作视频的时候有时比较让人头疼,定位时会发现只有一个<video>标签,用selenium来实现的话比较麻烦,使用js后我们只需定位到video标签 ...

  5. Python运维开发之路《python基础介绍》

    一. python介绍相关 1. Python简介 Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. - Python 的设计具有很强的可读性,相比其他语言经常使用英文关 ...

  6. NextJS项目的部署以及多环境的实现

    背景 开发了个Next项目,将部署过程记录一下.另外由于项目准备了两个服务器分别作为开发自测的开发环境和交付给客户的生产环境使用:因此也介绍一下NextJS项目中多环境的配置. 项目结构 计划是让Ng ...

  7. java.lang.IndexOutOfBoundsException

    原因:一个ArrayList数组中没有元素,而你想获取第一个元素,运行是就会报此类型的错误 解决方案:用 array[] 的  .length 查看 数组的长度

  8. GGTalk 开源即时通讯系统源码剖析之:数据库设计

    自从<开源即时通讯GGTalk 8.0发布,增加Linux客户端,支持在统信UOS.银河麒麟上运行!>一文在博客园发布后,有园友联系我QQ,说能不能整理个更系统更详细地介绍GGTalk源码 ...

  9. iOS CoreData总结

    相关主要类: NSManagedObjectContext 管理对象,上下文,持久性存储模型对象,处理数据与应用的交互 NSManagedObjectModel 被管理的数据模型,数据结构 NSPer ...

  10. Button按钮:得到鼠标焦点后自动放大,失去鼠标焦点后自动缩小_

    作用 程序设计过程中,我们经常需要增加一些动态效果,以此改善用户的使用体验.本文将介绍一种方法,动态显示按钮状态,使其得到鼠标焦点后自动放大,失去鼠标焦点后自动缩小. 效果图 先放一张原图(鼠标还未移 ...