關(guān)于Metalama使用Fabric操作項(xiàng)目或命名空間的問(wèn)題
Metalama中的Fabric可以做什么
Metalama是一個(gè)基于微軟編譯器Roslyn的元編程的庫(kù),可以解決我在開(kāi)發(fā)中遇到的重復(fù)代碼的問(wèn)題。但是其實(shí)Metalama不止可以提供編譯時(shí)的代碼轉(zhuǎn)換,更可以提供自定義代碼分析、與IDE結(jié)合的自定義代碼修復(fù)與代碼重構(gòu)功能 等功能。
經(jīng)過(guò)面對(duì)文檔的學(xué)習(xí),發(fā)現(xiàn)Metalama可以做到很多非常神奇的事情。
Fabric
通過(guò)修改項(xiàng)目、命名空間、類(lèi)型來(lái)達(dá)到一些效果,這引起修改包括:添加Aspect
或添加代碼分析
使用Fabric為指定的方法添加Aspect
前文中我們寫(xiě)過(guò)一個(gè)簡(jiǎn)單的Aspect
:
public class LogAttribute : OverrideMethodAspect { public override dynamic? OverrideMethod() { Console.WriteLine(meta.Target.Method.ToDisplayString() + " 開(kāi)始運(yùn)行."); var result = meta.Proceed(); Console.WriteLine(meta.Target.Method.ToDisplayString() + " 結(jié)束運(yùn)行."); return result; } }
當(dāng)我們使用它時(shí),我們要在對(duì)應(yīng)的方法上添加這個(gè)Attribute
:
[Log] private static int Add(int a, int b) //... ...
那么當(dāng)我們有一個(gè)Aspect
要在項(xiàng)目中大量使用時(shí),在每個(gè)方法上添加這個(gè)Aspect
當(dāng)然是一種方法,但是這種方法有2個(gè)缺點(diǎn):
- 包含大量的重復(fù)代碼
[Log]
- 對(duì)于原代碼的入侵性太強(qiáng)
此時(shí)我們就可以使用Fabric
為所有符合要求的方法添加指定的Aspect
:
internal class Fabric : ProjectFabric { // 這個(gè)是重寫(xiě)項(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添加代碼分析
上文中我們提到,我們可以通過(guò)Aspect
為代碼添加代碼分析,當(dāng)我們要將一個(gè)包含(且僅包含)代碼分析的Aspect
應(yīng)用于一批代碼時(shí),當(dāng)然我們可以按本文示例1
中的方法,直接使用Fabric
將包含代碼分析的Aspect
應(yīng)用于指定代碼。
但還有另外一種方法,我們可以直接在Fabric
中定義應(yīng)用于指定代碼的代碼分析。
下面示例,我們驗(yàn)證所有類(lèi)中的私有字段必須符合 _camelCase
,并且使用一個(gè)NamespaceFabric
來(lái)實(shí)現(xiàn):
namespace FabricCamelCaseDemo; class Fabric : NamespaceFabric { private static readonly DiagnosticDefinition<string> _warning = new( "DEMO04", Severity.Warning, "'{0}'必須使用駝峰命名法并以'_'開(kāi)頭"); // 這個(gè)是命名空間的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)绻诹硗庖粋€(gè)命名空間中定義一個(gè)違反規(guī)則的字段的話(huà),并不會(huì)有警告。
namespace FabricCamelCase; internal class OtherNamespace { int count = 0; int _total = 0; public int Add() { count++; _total++; return count + _total; } }
使用TypeFabric為類(lèi)型動(dòng)態(tài)添加方法
開(kāi)始前偽造一個(gè)需求,假設(shè)我有一個(gè)類(lèi)AddUtils
專(zhuān)門(mén)處理加法操作,它里面應(yīng)該有從2個(gè)到15個(gè)參數(shù)的Add方法15個(gè)(當(dāng)然我知道,可以使用params
等方法實(shí)現(xiàn),所以這里是個(gè)偽需求)。
最終效果為
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; } // 以此類(lèi)推... 下面省去若干方法 }
那么我們可以用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++) // 生成一個(gè)方法 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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ASP.NET操作各類(lèi)時(shí)間段獲取方法匯總
這篇文章主要介紹了ASP.NET操作各類(lèi)時(shí)間段獲取方法,實(shí)例匯總了各類(lèi)常見(jiàn)的時(shí)間段獲取方法,需要的朋友可以參考下2014-11-11Asp.Net Core利用文件監(jiān)視進(jìn)行快速測(cè)試開(kāi)發(fā)詳解
這篇文章主要給大家介紹了關(guān)于Asp.Net Core利用文件監(jiān)視進(jìn)行快速測(cè)試開(kāi)發(fā)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12.NET Core中創(chuàng)建和使用NuGet包的示例代碼
這篇文章主要介紹了.NET Core中創(chuàng)建和使用NuGet包的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04ASP.NET Core 數(shù)據(jù)保護(hù)(Data Protection)中篇
這篇文章主要為大家再一次介紹了ASP.NET Core 數(shù)據(jù)保護(hù)(Data Protection),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09使用 ServiceStack.Text 序列化 json的實(shí)現(xiàn)代碼
今天發(fā)篇文章總結(jié)下自己使用 ServiceStack.Text 來(lái)序列化 json。它的速度比 Newtonsoft.Json 快很多,在測(cè)試時(shí)發(fā)現(xiàn)比 fastJson 還快些2013-06-06ASP.NET MVC5網(wǎng)站開(kāi)發(fā)之登錄、驗(yàn)證和注銷(xiāo)管理員篇1(六)
這篇文章主要介紹了ASP.NET MVC5網(wǎng)站開(kāi)發(fā)之管理員登錄、驗(yàn)證和注銷(xiāo),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08ASP.NETCore6開(kāi)啟文件服務(wù)允許通過(guò)url訪(fǎng)問(wèn)附件的操作方法
最近在做一個(gè)工作臺(tái)的文件上傳下載功能,主要想實(shí)現(xiàn)上傳圖片之后,可以通過(guò)url直接訪(fǎng)問(wèn),由于url直接訪(fǎng)問(wèn)文件不安全,所以需要手動(dòng)開(kāi)啟文件服務(wù),這篇文章主要介紹了ASP.NETCore6開(kāi)啟文件服務(wù)允許通過(guò)url訪(fǎng)問(wèn)附件,需要的朋友可以參考下2023-11-11WPF使用VisualTreeHelper進(jìn)行命中測(cè)試
這篇文章介紹了WPF使用VisualTreeHelper進(jìn)行命中測(cè)試的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04異步 HttpContext.Current實(shí)現(xiàn)取值的方法(解決異步Application,Session,Cache.
在一個(gè)項(xiàng)目中,為了系統(tǒng)執(zhí)行效率更快,把一個(gè)經(jīng)常用到的數(shù)據(jù)庫(kù)表通過(guò)dataset放到Application中,發(fā)現(xiàn)在異步實(shí)現(xiàn)中每一次都會(huì)出現(xiàn)HttpContext.Current為null的異常,后來(lái)在網(wǎng)上查了好多資料,發(fā)現(xiàn)問(wèn)這個(gè)問(wèn)題的人多,回答的少2009-07-07