關(guān)于Metalama使用Fabric操作項(xiàng)目或命名空間的問題
Metalama中的Fabric可以做什么
Metalama是一個基于微軟編譯器Roslyn的元編程的庫,可以解決我在開發(fā)中遇到的重復(fù)代碼的問題。但是其實(shí)Metalama不止可以提供編譯時的代碼轉(zhuǎn)換,更可以提供自定義代碼分析、與IDE結(jié)合的自定義代碼修復(fù)與代碼重構(gòu)功能 等功能。
經(jīng)過面對文檔的學(xué)習(xí),發(fā)現(xiàn)Metalama可以做到很多非常神奇的事情。
Fabric通過修改項(xiàng)目、命名空間、類型來達(dá)到一些效果,這引起修改包括:添加Aspect或添加代碼分析
使用Fabric為指定的方法添加Aspect
前文中我們寫過一個簡單的Aspect:
public class LogAttribute : OverrideMethodAspect
{
public override dynamic? OverrideMethod()
{
Console.WriteLine(meta.Target.Method.ToDisplayString() + " 開始運(yùn)行.");
var result = meta.Proceed();
Console.WriteLine(meta.Target.Method.ToDisplayString() + " 結(jié)束運(yùn)行.");
return result;
}
}當(dāng)我們使用它時,我們要在對應(yīng)的方法上添加這個Attribute:
[Log] private static int Add(int a, int b) //... ...
那么當(dāng)我們有一個Aspect要在項(xiàng)目中大量使用時,在每個方法上添加這個Aspect當(dāng)然是一種方法,但是這種方法有2個缺點(diǎn):
- 包含大量的重復(fù)代碼
[Log] - 對于原代碼的入侵性太強(qiáng)
此時我們就可以使用Fabric為所有符合要求的方法添加指定的Aspect:
internal class Fabric : ProjectFabric
{
// 這個是重寫項(xiàng)目的Fabric中修改項(xiàng)目的方法
public override void AmendProject(IProjectAmender amender)
{
// 添加 LogAttribute 到符合規(guī)則的方法上
// 為名為 Add 且 private 的方法添加 LogAttribute
amender.WithTargetMembers(c =>
c.Types.SelectMany(t => t.Methods)
.Where(t =>
t.Name == "Add" &&
t.Accessibility == Metalama.Framework.Code.Accessibility.Private)
).AddAspect(t => new LogAttribute());
}
}
這樣就可以在不入侵現(xiàn)有代碼的情況下為指定的方法添加Aspect。
使用Fabric添加代碼分析
上文中我們提到,我們可以通過Aspect為代碼添加代碼分析,當(dāng)我們要將一個包含(且僅包含)代碼分析的Aspect應(yīng)用于一批代碼時,當(dāng)然我們可以按本文示例1中的方法,直接使用Fabric將包含代碼分析的Aspect應(yīng)用于指定代碼。
但還有另外一種方法,我們可以直接在Fabric中定義應(yīng)用于指定代碼的代碼分析。
下面示例,我們驗(yàn)證所有類中的私有字段必須符合 _camelCase,并且使用一個NamespaceFabric來實(shí)現(xiàn):
namespace FabricCamelCaseDemo;
class Fabric : NamespaceFabric
{
private static readonly DiagnosticDefinition<string> _warning = new(
"DEMO04",
Severity.Warning,
"'{0}'必須使用駝峰命名法并以'_'開頭");
// 這個是命名空間的Fabric中修改命名空間規(guī)則 的方法
public override void AmendNamespace(INamespaceAmender amender)
{
// 取所有非static 的private的字段,并添加代碼分析
amender.WithTargetMembers(c =>
c.AllTypes.SelectMany(t=>t.Fields)
.Where(t => t.Accessibility == Accessibility.Private && !t.IsStatic
)
)
//preview 0.5.8之前為 RegisterFinalValidator
.Validate(this.FinalValidator);
}
private void FinalValidator(in DeclarationValidationContext context)
{
var fullname = context.Declaration.ToDisplayString();
var fieldName = fullname.Split('.').LastOrDefault();
if (fieldName!=null && (!fieldName.StartsWith("_") || !char.IsLower(fieldName[1])))
{
context.Diagnostics.Report(_warning.WithArguments(fieldName));
}
}
}
當(dāng)然因?yàn)楫?dāng)前使用的是NamespaceFabric所以該規(guī)則只應(yīng)用于當(dāng)前命名空間如,我們?nèi)绻诹硗庖粋€命名空間中定義一個違反規(guī)則的字段的話,并不會有警告。
namespace FabricCamelCase;
internal class OtherNamespace
{
int count = 0;
int _total = 0;
public int Add()
{
count++;
_total++;
return count + _total;
}
}
使用TypeFabric為類型動態(tài)添加方法
開始前偽造一個需求,假設(shè)我有一個類AddUtils專門處理加法操作,它里面應(yīng)該有從2個到15個參數(shù)的Add方法15個(當(dāng)然我知道,可以使用params等方法實(shí)現(xiàn),所以這里是個偽需求)。
最終效果為
public class AddUtils
{
public int Add2(int x1, int x2)
{
var result = 0;
result += x1;
result += x2;
return 2;
}
public int Add3(int x1, int x2, int x3)
{
var result = 0;
result += x1;
result += x2;
result += x3;
return 3;
}
// 以此類推... 下面省去若干方法
}那么我們可以用Metalama如此實(shí)現(xiàn)
using System.Reflection.Emit;
using Metalama.Framework.Aspects;
using Metalama.Framework.Fabrics;
public class AddUtils
{
private class Fabric : TypeFabric
{
// 實(shí)現(xiàn)的方法體
[Template]
public int MethodTemplate()
{
var num = (int) meta.Tags["nums"]!;
var result = 0;
foreach (var targetParameter in meta.Target.Parameters)
{
result += targetParameter.Value;
}
return num;
}
public override void AmendType(ITypeAmender amender)
for (var i = 2; i < 15; i++)
// 生成一個方法
var methodBuilder = amender.Advices.IntroduceMethod(
amender.Type,
nameof(this.MethodTemplate),
tags: new TagDictionary { ["nums"] = i });
// 方法名
methodBuilder.Name = "Add" + i;
// 添加參數(shù)
for (int parameterIndex = 1; parameterIndex <= i; parameterIndex++)
{
methodBuilder.AddParameter($"x{parameterIndex}", typeof(int));
}
}
}引用
本章源代碼:https://github.com/chsword/metalama-demo
Metalama官方文檔: https://doc.metalama.net/
Metalama Nuget包: https://www.nuget.org/packages/Metalama.Framework/0.5.11-preview
到此這篇關(guān)于Metalama使用Fabric操作項(xiàng)目或命名空間的文章就介紹到這了,更多相關(guān)Metalama操作項(xiàng)目或命名空間內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
asp.net配置會話狀態(tài)Session實(shí)現(xiàn)代碼
在Web應(yīng)用程序中,都會有一個Web.config文件來配置當(dāng)前Web項(xiàng)目。其中包括關(guān)于會話狀態(tài)Session的配置2012-10-10
ASP.NET對HTML頁面元素進(jìn)行權(quán)限控制(一)
界面每個元素的權(quán)限也是需要控制的。比如一個查詢用戶的界面里面有查詢用戶按鈕,添加用戶按鈕,刪除用戶按鈕,不同的角色我們得分配不同的權(quán)限2013-12-12
.net SMTP發(fā)送Email實(shí)例(可帶附件)
本文為大家詳細(xì)介紹下.net SMTP發(fā)送Email同時可帶附件的具體實(shí)現(xiàn)思路及代碼,想實(shí)現(xiàn)的朋友可以參考下哈,希望對大家有所幫助2013-07-07
Asp.net MVC利用knockoutjs實(shí)現(xiàn)登陸并記錄用戶的內(nèi)外網(wǎng)IP及所在城市(推薦)
這篇文章主要介紹了 Asp.net MVC利用knockoutjs實(shí)現(xiàn)登陸并記錄用戶的內(nèi)外網(wǎng)IP及所在城市(推薦),需要的朋友可以參考下2017-02-02
輕量級ORM框架Dapper應(yīng)用支持操作函數(shù)和事物
這篇文章介紹了Dapper支持操作函數(shù)和事物的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-03-03
asp.net基于windows服務(wù)實(shí)現(xiàn)定時發(fā)送郵件的方法
這篇文章主要介紹了asp.net基于windows服務(wù)實(shí)現(xiàn)定時發(fā)送郵件的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了asp.net調(diào)用Windows系統(tǒng)服務(wù)的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11

