使用基于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. ClassNotFoundException: javax.persistence.Converter

    检查你的hibernate-jpa-2.0-api-1.0.0.final.jar,会发现javax.persitence包中没有Convert类. 解决办法:下载hibernate-jpa-2.1- ...

  2. 数组有没有 length()方法?String 有没有 length()方法?

    数组没有 length()方法,有 length 的属性. String 有 length()方法.JavaScript中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混 ...

  3. 简易shell脚本启动jar包

    可参考博客: Shell脚本中$0.$?.$!.$$.$*.$#.$@等的意义    https://blog.csdn.net/csgd2000/article/details/80396996 s ...

  4. Kali Linux 下安装配置MongoDB数据库 ubuntu 下安装配置MongoDB源码安装数据库

    Kali Linux 下安装配置MongoDB数据库   1.下载mongodb.tgz 压缩包: 2.解压到:tar -zxvf mongodb.tgz /usr/local/mongodb 3.创 ...

  5. ROS学习文章

    ros机器人到底有没有必要学习?

  6. 1108. IP 地址无效化

    给你一个有效的 IPv4 地址 address,返回这个 IP 地址的无效化版本. 所谓无效化 IP 地址,其实就是用 "[.]" 代替了每个 ".". 示例 ...

  7. SCSS学习笔记(一)

    SCSS的由来 SCSS就是加强版的CSS,要讲SCSS那就一定要从SASS讲起 SASS Sass(英文全称:Syntactically Awesome Stylesheets)是一个最初由Hamp ...

  8. java中为什么接口中的属性和方法都默认为public?

    4)为什么接口中的属性和方法都默认为public?Sun公司当初为什么要把java的接口设计发明成这样? [新手可忽略不影响继续学习]答:如上所述,马克-to-win:既然接口强于抽象类能胜任作为和外 ...

  9. python用户交互与基本运算符

    与用户交互 输入 获取用户输入 username = input('请输入您的用户名>>>:') '''将input获取到的用户输入绑定给变量名username''' print(u ...

  10. java_抽象类和接口

    1.抽象类: 1.抽象类之所以被称为抽象类,就是因为它包含有抽象方法,只要含有抽象方法的类就叫抽象类. 2.抽象类中可以没有抽象方法,也可以抽象方法和非抽象方法共存. 3.抽象类和类一样是单继承的. ...