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

Metalama简介1. 不止是一个.NET跨平台的编译时AOP框架

Metalama简介2.利用Aspect在编译时进行消除重复代码

Metalama简介3.自定义.NET项目中的代码分析

Metalama简介4.使用Fabric操作项目或命名空间

在Visual Studio中有提供快速操作(小灯泡)功能

以及重构(小刷子)功能

使用它们可以快速进行一些快捷的针对代码的操作,如提取接口、添加实现、自动属性、快速重构、删除引用等。

除官方提供的功能外我们还可以使用很多第三方插件来支持更多地功能。

Metalama可以通过编写代码的形式,让我们为指定的代码添加重构或快速操作的功能。

自定义一个ToString的实时模板

很多图形编程或游戏编程中,我们会用到各种自定义类如矩阵、复数、坐标系等,为了方便Debug,我们通常会为这些类增加一个ToString方法的重写。

例如

internal class Program
{
private static void Main()
{
var point = new Point { X = 5, Y = 3};
Console.WriteLine($"point = {point}");
}
}
internal class Point
{
public double X;
public double Y;
public override string ToString()
{
return $"({X}, {Y})";
}
}

如果我们不想手写这个ToString方法,而想让VS直接为它生成。

则我们可以使用Metalama定义一个LiveTemplate,这样就可以在VS的工具中使用它了。

[LiveTemplate] // 表示当前Aspect为VS添加LiveTempate
internal class ToStringAttribute : TypeAspect
{
[Introduce(WhenExists = OverrideStrategy.Override, Name = "ToString")]
public string IntroducedToString()
{
var stringBuilder = new InterpolatedStringBuilder();
stringBuilder.AddText("{ ");
stringBuilder.AddText(meta.Target.Type.Name);
stringBuilder.AddText(" "); var fields = meta.Target.Type.FieldsAndProperties.Where(f => !f.IsStatic).ToList(); var i = meta.CompileTime(0); foreach (var field in fields)
{
if (i > 0)
{
stringBuilder.AddText(", ");
} stringBuilder.AddText(field.Name);
stringBuilder.AddText("=");
stringBuilder.AddExpression(field.Invokers.Final.GetValue(meta.This)); i++;
} stringBuilder.AddText(" }"); return stringBuilder.ToValue();
}
}

这样在,下列代码中使用重构功能,即可看到Metalama给的实时代码提示。

internal class Point
{
public double X;
public double Y;
}

使用Metalama添加一个VisualStudio的快速操作

我们最终的目的如下,对于标注了[Tostring]的类,增加一个将[ToString]切换至手动实现的功能点击后可实现自动添加一个ToString:

这需要我们在Aspect``ToStringAttribute中添加一个提示:

public class ToStringAttribute : TypeAspect
{
public override void BuildAspect(IAspectBuilder<INamedType> builder)
{
base.BuildAspect(builder);
// 添加一个建议手动实现的重构提示
if (builder.AspectInstance.Predecessors[0].Instance is IAttribute attribute)
{
builder.Diagnostics.Suggest(
new CodeFix("将 [ToString] 切换至手动实现", codeFixBuilder => this.ImplementManually(codeFixBuilder, builder.Target)),
builder.Target);
}
} /// <summary>
/// 当点击手动实现时的操作
/// </summary>
private async Task ImplementManually(ICodeActionBuilder builder, INamedType targetType)
{
await builder.ApplyAspectAsync(targetType, this);
await builder.RemoveAttributesAsync(targetType, typeof(ToStringAttribute));
} [Introduce(WhenExists = OverrideStrategy.Override, Name = "ToString")]
public string IntroducedToString()
{
// 获取非静态字段
var fields = meta.Target.Type.FieldsAndProperties.Where(f => !f.IsStatic).ToList(); // 构建一个$""字符串
var stringBuilder = new InterpolatedStringBuilder();
stringBuilder.AddText("{ ");
stringBuilder.AddText(meta.Target.Type.Name);
stringBuilder.AddText(" "); var i = meta.CompileTime(0); foreach (var field in fields)
{
if (i > 0)
{
stringBuilder.AddText(", ");
} stringBuilder.AddText(field.Name);
stringBuilder.AddText("=");
stringBuilder.AddExpression(field.Invokers.Final.GetValue(meta.This)); i++;
} stringBuilder.AddText(" }");
return stringBuilder.ToValue();
}
}

这样就可以对于已经添加了[ToString]的类实现以上功能

[ToString]
internal class Point // 在此处触发 Ctrl+.或右键
{
public double X;
public double Y;
}

引用

本章源代码:https://github.com/chsword/metalama-demo

Metalama官方文档: https://doc.metalama.net/

Metalama Nuget包: https://www.nuget.org/packages/Metalama.Framework/0.5.13-preview

Metalama简介5.配合VisualStudio自定义重构或快速操作功能的更多相关文章

  1. Metalama简介3.自定义.NET项目中的代码分析

    本系列其它文章 使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题 Metalama简介1. 不止是一个.NET跨平台的编译时AOP框架 Metalama简介2.利用Aspect在 ...

  2. Metalama简介4.使用Fabric操作项目或命名空间

    使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题 Metalama简介1. 不止是一个.NET跨平台的编译时AOP框架 Metalama简介2.利用Aspect在编译时进行消除重 ...

  3. Metalama简介2.利用Aspect在编译时进行消除重复代码

    上文介绍到Aspect是Metalama的核心概念,它本质上是一个编译时的AOP切片.下面我们就来系统说明一下Metalama中的Aspect. Metalama简介1. 不止是一个.NET跨平台的编 ...

  4. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(四):自定义T4模板快速生成页面

    前言:上篇介绍了下ko增删改查的封装,确实节省了大量的js代码.博主是一个喜欢偷懒的人,总觉得这些基础的增删改查效果能不能通过一个什么工具直接生成页面效果,啥代码都不用写了,那该多爽.于是研究了下T4 ...

  5. 3D触控简介:建立数字刻度应用及快速活动栏

    苹果公司通过 iPhone 6s 和 6s Plus 引入了与手机互动的全新方式:按压手势.你也许知道,苹果智能手表和苹果笔记本电脑早已具备这一功能,只是名称略有不同,为力感触控(Force Touc ...

  6. fragment、ListFragment使用ListView及自定义Listview等初始化操作

    fragment.ListFragment使用ListView及自定义Listview等初始化操作 1.先说一下 从官方api中说fragment碎片中使用Listview有专门的 ListView碎 ...

  7. VS code配置go语言开发环境之自定义快捷键及其对应操作

    VS code 配置 自定义快捷键 及其对应操作   由于 vs code 的官方 go 插件不支持像 goland 一样运行当前 go 文件, 只能项目 或者 package 级别地运行, 因此有必 ...

  8. 获取浏览器弹窗alert、自定义弹窗以及其操作

    web自动化测试第10步:获取浏览器弹窗alert.自定义弹窗以及其操作 - CSDN博客 http://blog.csdn.net/ccggaag/article/details/76573857 ...

  9. Phoenix简介概述,Phoenix的Java API 相关操作优秀案例

    Phoenix简介概述,Phoenix的Java API 相关操作优秀案例 一.Phoenix概述简介 二.Phoenix实例一:Java API操作 2.1 phoenix.properties 2 ...

随机推荐

  1. Oracle入门基础(十二)一一储存过程及触发器

    1.第一个存储过程 打印Hello World 调用存储过程: 1.exec sayhelloworld(); 2.begin sayhelloworld(); sayhelloworld(); en ...

  2. MySQL安装速成指南(ZIP)

    MySQL初始化数据库 第一步:将MySQL ZIP压缩包进行解压 第二部:在MySQL主目录创建my.ini文件,并添加以下内容 [client] port=3306 socket=/tmp/mys ...

  3. ElasticSearch-学习笔记01-docker安装

    安装ElasticSearch docker 安装请参考: https://www.cnblogs.com/youxiu326/p/docker-01.html docker run -d --nam ...

  4. ctfhub 双写绕过 文件头检查

    双写绕过 进入环境 上传一句话木马 上传路径感觉不对检查源代码 从此处可以看出需要双写绕过 使用bp抓包 此处这样修改即可双写绕过 使用蚁剑连接 即可找到flag 文件头检查 进入环境 上传一句话木马 ...

  5. Vue的computed(计算属性)使用实例之TodoList

    最近倒腾了一会vue,有点迷惑其中methods与computed这两个属性的区别,所以试着写了TodoList这个demo,(好土掩面逃~); 1. methods methods类似react中组 ...

  6. onsubmit阻止表单提交

    在实际开发中往往会遇到检查表单数据的合法性,如果数据不合法,就不让其提交. <!DOCTYPE html> <html> <head> <meta chars ...

  7. JavaScript作用域链与闭包的理解

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域 链的工作原理. 1. 全局作用域(Global Scope) (1)最外层函数和 ...

  8. sring框架的jdbc应用

      xml配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http: ...

  9. datetimepicker 设置日期格式、初始化

    $('#datetimepicker').datetimepicker({ minView: "month", //选择日期后,不会再跳转去选择时分秒 language: 'zh- ...

  10. MySQL安装配置教程(超级详细)

    一. 下载MySQL Mysql官网下载地址:https://downloads.mysql.com/archives/installer/ 1. 选择要安装的版本,本篇文章选择的是5.7.31版本, ...