使用基于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. 【算法篇】Bitmap 算法

    首先,什么是Bitmap算法(位图算法)呢? 一:定义: Bit map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素.使用Bit为用来存储数据的单位, 可以大大节省存储空间. ...

  2. springboot 设定访问项目的根路径

    springboot的配置文件application.yml: spring.mvc.view.prefix : / spring.mvc.view.suffix : .html server: po ...

  3. 什么是RabbitMQ?RabbitMQ的使用场景是什么?

    参考链接:RabbitMQ 简介以及使用场景

  4. 如何实现集群中的 session 共享存储?

    Session 是运行在一台服务器上的,所有的访问都会到达我们的唯一服务器上,这 样我们可以根据客户端传来的 sessionID,来获取 session,或在对应 Session 不 存在的情况下(s ...

  5. ACM - 最短路 - AcWing 849 Dijkstra求最短路 I

    AcWing 849 Dijkstra求最短路 I 题解 以此题为例介绍一下图论中的最短路算法.先让我们考虑以下问题: 给定一个 \(n\) 个点 \(m\) 条边的有向图(无向图),图中可能存在重边 ...

  6. h5 在全屏iphonex中的适配

    iphonex 已经上线有一段时间了,作为业界刘海屏幕第一款机型,导致全屏不能正常的全屏显示了,,所以需要对iphonx 适配,下面就详细说说如何适配 先看一张适配前后的图: iphonex 提供的 ...

  7. css设置图片根据最大边自适应

    给新手的福利,还是记一下吧.......很简单 <div> <img src="1.jpg" alt=""> </div> ...

  8. JavaScript实现表单的校验以及匹配正则表达式

    运行效果: 未填写信息报错: 匹配正则表达式: 信息校验无误: 源代码如下: 1 <!DOCTYPE html> 2 <html lang="zh"> 3 ...

  9. jq移动端图片预览 (fly-zomm-img.js)

    效果图: ===>==> 里面还与很多属性设置: index  关闭按钮等等 代码: //html-----------------------<div class="he ...

  10. 腾讯云服务nginx部署静态项目

    一直想要搭建自己的blog,买了基础云服务器练手 文章内容是根据腾讯文档(https://cloud.tencent.com/document/product/213/2131)总结 部署静态页面归纳 ...