使用基于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
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/469437.html
標籤:.NET技术
上一篇:C#自定義組態檔(一)