使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题

理想的代码优化方式

团队日常协作中,自然而然的会出现很多重复代码,根据这些代码的种类,之前可能会以以下方式处理

方式描述应用时可能产生的问题
硬编码多数新手,或逐渐腐坏的项目会这么干,会直接复制之前实现的代码带来的问题显而易见的多,例如架构会逐渐随时间被侵蚀,例外越来越多
提取函数提取成为函数,然后复用提取函数,然后复用,会比直接硬编码好些,但是仍然存在大量因“例外”而导致增加参数、增加函数重载的情况
模板生成器CodeSmith/T4等因为是独立进程,所以对于读取用户代码或项目,实现难度较高,且需要现有用户项目先生成成功,再进行生成 ,或者是完全基于新项目
代码片段VS自带的代码片段功能无法对复杂的环境或条件做出响应
AOP框架面向切面编程,可以解决很多于用户代码前后增加操作的事情但是大多AOP框架都是基于透明代理形式实现的,对于相互调用较多的代码,但形成性能压力,而且因为要符合透明代理的规则,所以要提供相应的子类或接口。

基于Rosyln的编译时插入代码

但以上这几种,AOP算是最理想的方式,但是感觉上还可以有更好的解决方案。

直到读到了这篇文章 Introducing C# Source Generators,文中提供了一种新的解决方案,即通过RoslynSource Generator在编译时直接读取当前项目中的语法树,处理并生成的新代码,然后在编译时也使用这些新代码。

那么如果可以读取现有代码的语法树,通过读取代码中的标记,那么在代码生成过程中是否就能直接生成。
实现如下效果:
项目中的源代码 Program.cs

internal class Program
{
[Log]
private static int Add( int a, int b )
{
return a + b;
}
}

自动根据 LogAttribute 自动编译成的代码 Program.g.cs

internal class Program
{
[Log]
private static int Add( int a, int b )
{
Console.WriteLine("Program.Add(int, int) 开始运行.");
int result;
result = a + b;
Console.WriteLine("Program.Add(int, int) 结束运行.");
return result;
}
}

当然LogAttribute中需要去实现插入代码。
然后项目自动使用新生成的Program.g.cs进行编译。这样就实现了基于编译时的AOP。

即实现以下流程
a70ffec2908a2394de5fd31067b5e7ae.png

使用Metalama实现以上流程

经过寻找,发现其实已经有框架可以实现我上面说的流程了,也就是在编译时实现代码的插入。
https://www.postsharp.net/metalama 。

下面作一个简单示例

  1. 创建一个.NET6.0的控制台应用,我这里命名为LogDemo,
    其中的入口文件Program.cs

namespace LogDemo {
public class Program
{
public static void Main(string[] args)
{
var r = Add(1, 2);
Console.WriteLine(r);
}
// 这里写一个简单的方法,一会对这个方法进行代码的插入
private static int Add(int a, int b)
{
var result = a + b;
Console.WriteLine("Add" + result);
return result;
}
}
}
  1. 在项目中使用Metalama

通过引用包 https://www.nuget.org/packages/Metalama.Framework, 注意Metalama当前是Preview版本,如果通过可视化Nuget管理器引入,需要注意勾选包含预发行版

dotnet add package Metalama.Framework --version 0.5.7-preview
  1. 编写一个AOP的Attribute

在项目中引入 Metalama.Framework后无需多余配置或代码,直接编写一个AOP的Attribute

using Metalama.Framework.Aspects;namespace LogDemo {
public class Program
{
public static void Main(string[] args)
{
var r = Add(1, 2);
Console.WriteLine(r);
}
// 在这个方法中使用了下面的Attribute
[LogAttribute]
private static int Add(int a, int b)
{
var result = a + b;
Console.WriteLine("Add" + result);
return result;
}
}
// 这里是增加的 Attribute
public class LogAttribute : OverrideMethodAspect
{
public override dynamic? OverrideMethod()
{
Console.WriteLine(meta.Target.Method.ToDisplayString() + " 开始运行.");
var result = meta.Proceed();
Console.WriteLine(meta.Target.Method.ToDisplayString() + " 结束运行.");
return result;}
}
}
  1. 执行结果如下

Program.Add(int, int) 开始运行.
Add3
Program.Add(int, int) 结束运行.
3
  1. 生成的程序集进行反编译,得到的代码如下:

using Metalama.Framework.Aspects;
namespace LogDemo {
public class Program
{
public static void Main(string[] args)
{
var r = Add(1, 2);
Console.WriteLine(r);
}
// 在这个方法中使用了下面的Attribute
[LogAttribute]
private static int Add(int a, int b)
{
Console.WriteLine("Program.Add(int, int) 开始运行.");
int result_1;
var result = a + b;
Console.WriteLine("Add" + result);
result_1 = result;
Console.WriteLine("Program.Add(int, int) 结束运行.");
return result_1;
}
}
#pragma warning disable CS0067
// 这里是增加的 Attribute
public class LogAttribute : OverrideMethodAspect
{
public override dynamic? OverrideMethod() =>
throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
}
#pragma warning restore CS0067
}

总结

这样就完全实现了我之前想要的效果,当然使用Metalama还可以实现很多能极大地提高生产力的功能,它不仅可以对方法进行改写,也可以对属性、字段、事件、甚至是类、命名空间进行一些操作 。

引用

Introducing C# Source Generators:https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/
Metalama官网:https://www.postsharp.net/metalama

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/289227.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React Native之Flexbox布局和监测文本输入onChangeText

1 Flexbox布局 1) flexDirection 可以决定布局的主轴,子元素是应该沿着水平轴(row)方向排列,还是沿着竖直轴(column)方向排列 2) justifyContent 决定其子元素沿着次轴(与主轴垂直的轴,比如若主轴方向为row,则次轴方向为…

半年总结——欲戴王冠,必承其重

【Introduction】 每一个女生都梦想着作为一个女王。但是你仅仅看到了女王头上金闪闪的王冠,却不知道在这个王冠下。她是怎样成长的!假设你想要做到有女王一样的权利,就必需要承担一个女王应该做到的事情!——欲带王冠&#xff0c…

SQL日期时间格式自由转换大全

日期数据格式的处理,两个示例: CONVERT(varchar(16), 时间一, 20) 结果:2007-02-01 08:02/*时间一般为getdate()函数或数据表里的字段*/ CONVERT(varchar(10), 时间一, 23) 结果:2007-02-01 /*varchar(10)表示日期输出的格式,如果不够长会发生截取*/

一维数组和二维数组的区别_数组指针和指针数组的区别

数组指针和指针数组的区别 - hongcha_717 - 博客园​www.cnblogs.com数组指针(也称行指针)定义 int (*p)[n];()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的…

mysql 配置多个数据库连接_总结MySQL修改最大连接数的两个方式

问题在使用MySQL数据库的时候,经常会遇到这么一个问题,就是“Can not connect to MySQL server. Too many connections”-mysql 1040错误,这是因为访问MySQL且还未释放的连接数目已经达到MySQL的上限。通常,mysql的最大连接数默认…

饿了么超级会员,年卡低至108元!饿了么会员,点外卖超省钱!

饿了么是大家常用的外卖平台,经常点外卖的朋友,充个饿了么超级吃货卡,还是能省不少钱的,今天给大家带来饿了么会员特价充值,会员秒到!饿了么超级会员特价充值月卡:原价15元,特价仅需…

React Native之内部方法常用几种写法和调用规则

1 简单部分代码 export default class App extends Component<Props> {render() {return (<View style{styles.container}><View style{styles.welcome}><Button onPress{this.showMsg}titleprees me showMsg/> <Button onPress{() > {this.sho…

阿里云欧洲数据中心开放运营:与沃达丰达成战略合作

摘要&#xff1a;近日&#xff0c;阿里云在德国宣布正式登陆欧洲市场&#xff0c;其位于欧洲的数据中心正式开放运营&#xff0c;同时与沃达丰达成战略合作&#xff0c;携手为欧洲提供云计算服务&#xff0c;并为中国企业进入欧洲市场提供互联网基础设施便利。 据悉&#xff0c…

C#ListView控件添加复选框并获取选中的数目

1、添加复选框:listView1.CheckBoxes = true; 2、选中listview并获取选中的数目: private void listView1_ItemChecked(object sender, ItemCheckedEventArgs e){e.Item.Selected = e.Item.Checked;m = listView1.CheckedItems.Count;label1.Text = "当前选中数:"…

MFS学习总结

MFS学习总结 MFS概述、特性和新版改进MFS 工作原理和设计架构MFS的安装、部署、配置MFS的高级特性MFS的性能测试MFS集群的维护MFS的常见问题和建议对策一、MFS概述、特性和新版改进 MooseFS是一个分布式存储的框架&#xff0c;其具有如下特性&#xff1a; Free(GPL)通用文件系统…

python打开csv文件乱码_python脚本解决csv文件用excel打开乱码

import os path csv文件路径 targetPath 转换编码保存路径 def getfiles(path): path_collection[] for dirpath,dirnames,filenames in os.walk(path): for file in filenames: fullpathos.path.join(dirpath,file) path_collection.append(fullpath) return path_collection…

Linux - 命令

1、查看目录下有什么文件/目录操作 > ls //list列出目录文件的信息 > ls -l //list -list 以“详细信息”查看目录文件 > ls -a //list -all查看目录“全部&#xff08;包括隐藏文件&…

c 编程 mysql结果集_使用mysql C语言API编写程序—MYSQL数据库查询操作(执行查询操作,获取查询结果的字段数,记录行数,...

//MYSQL_RES保存查询结构MYSQL_RES*result_ NULL;interror_code 0; //保存错误码charerror_info[1024] \0; //保存错误信息//对mysql数据库进行查询操作:charquery_sql[1024] "select * from db_name.table_name";//构建查询sql语句if(result_! NULL) //防止之前…

介绍一款受欢迎的.NET 开源UI库

概述今天要带大家了解的是一款WPF的开源控件库MahApps.Metro。MahApps.Metro是用于创建现代WPF应用程序的工具包&#xff0c;它许多开箱即用的好东西。目前支持的NET Framework 4.6.2及更高版本、.NET Core 3.1, .NET 5 and .NET 6 (on Windows)。官网学习文档地址&#xff1a;…

图像分类中混淆矩阵精度验证法中的几个指标说明

ToolBox->Classification->PostClassification->Confusion Matrix->Using Ground Truth ROIs,可以得到如下的分类精度验证的混淆矩阵。 要看懂这个精度验证结果,需要了解几个混淆矩阵中的几项评价指标:

React Native之触摸事件(Touchable系列和onLongPress)

1 触摸事件 普通点击我们可以使用onPress方法,我们可以使用Touchable 系列控件设计我们的按钮 TouchableHighlight 背景会在用户手指按下时变暗 TouchableNativeFeedback用户手指按下时形成类似墨水涟漪的视觉效果 TouchableOpacity指按下时降低按钮的透明度&#xff0c;而…

社交背水一战?校园日记背后,支付宝野心你真能懂?

“校园日记”昨天火了一天&#xff0c;我们也是时候来聊聊支付宝背后的具体战略和意图了。今天早上看到虎嗅的头条《支付宝的“圈子”&#xff0c;阿里做社交的背水一战》&#xff0c;文章观点主要分析了支付宝做社交的必要性&#xff0c;以及这次切入社交领域的巧妙性。 这篇文…

WebForm 使用点滴。。。。

WebForm使用方式与WinForm很是相似&#xff0c;可控性非常高&#xff01; 1、调用别的按钮事件&#xff1a; BtnSelect_Click(sender, e);转载于:https://www.cnblogs.com/chenmfly/p/4409447.html

System.FormatException: GUID 应包含带 4 个短划线的 32 位数(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)。...

在NHibernate数据库查询中出现了这个错误&#xff0c;由于是数据库是mysql的&#xff0c;当定义的字段为char(36)的时候就会出现这个错误。 【解决方法】 将char(36) 改成varchar(40)就行了 参考&#xff1a;http://www.cnblogs.com/end/archive/2012/12/26/2834068.html转载于…

python3文件的编码类型是什么_Python3编码类型有哪些?怎么转换?

经过小伙伴们的提醒&#xff0c;小编发现编码方面少讲了一个基础知识&#xff0c;所以有的小伙伴对这方面的内容比较模糊&#xff0c;这就让小编有点尴尬了。收到大家的催促&#xff0c;小编马上就整理出了编码类型的资料&#xff0c;内容方面都是经过精简的&#xff0c;便于小…