Metalama簡介3.自定義.NET項目中的代碼分析

来源:https://www.cnblogs.com/chsword/archive/2022/04/13/metalama_3.html
-Advertisement-
Play Games

本文介紹,如何使用Metalama庫對.NET項目添加自定義的代碼分析,即自定義的編譯時警告、錯誤 ...


本系列其它文章

使用基於Roslyn的編譯時AOP框架來解決.NET項目的代碼復用問題
Metalama簡介1. 不止是一個.NET跨平臺的編譯時AOP框架
Metalama簡介2.利用Aspect在編譯時進行消除重覆代碼

代碼分析

這裡所說的代碼分析,是可以通過一些自定義的方法,在使用不符合條件的代碼時產生錯誤或警告。
如果配合CI併在每次持續集成時,都向團隊分發警告和錯誤。團隊也在開發時遵守誰產生的警告,誰解決的團隊約定,那麼團隊將不斷減少技術債務,這樣可以避免架構持續性的腐壞。

image

當然.NET自身及一些三方工具如Resharper已經提供了很多的代碼分析功能,包括但不限於命名、代碼調用等。但是有時想要更近一步地為團隊增加更加定製化地代碼分析,卻沒有對應的辦法。

Metalama中也提供了代碼分析功能。

下麵我們以幾個示例來演示Metalama中如何使用代碼分析。

通用自定義代碼分析示例Logger

(源碼見最後)
以我們最初的Log示例為例,假設我們當前要引入ILogger來記錄日誌,來替換當前的Console.WriteLine

interface ILogger
{
    void Info(string message);
}
public class ConsoleLogger : ILogger
{
    public void Info(string message)
    {
        Console.WriteLine(message);
    }
}

那麼Program也要做出修改。

class Program
{
    ILogger _logger = new ConsoleLogger();
    public static void Main(string[] args)
    {
        var r = new Program().Add(1, 2);
        Console.WriteLine(r);
    }
    // 在這個方法中使用了下麵的Attribute
    [LogAttribute]
    private int Add(int a, int b)
    {
        var result = a + b;
        return result;
    }
}

LogAttribute也要進行修改。

public class LogAttribute : OverrideMethodAspect
{
    public override dynamic? OverrideMethod()
    {
        meta.This._logger.Info(meta.Target.Method.ToDisplayString() + " 開始運行.");
        var result = meta.Proceed();
        meta.This._logger.Info(meta.Target.Method.ToDisplayString() + " 結束運行.");
        return result;
    }
}

接下來我們可以為LogAttribute添加代碼分析,要求LogAttribute的方法的所在的類上,必須有_logger且類型必須為ILogger

public class LogAttribute : OverrideMethodAspect
{
    static DiagnosticDefinition<(INamedType DeclaringType, IMethod Method)> _loggerFieldNotFoundError = new(
    "DEMO01",
    Severity.Error,
    "類型'{0}'必須包含ILogger類型的欄位 '_logger'因為使用了[Log]Aspect在'{1}'上.");

    // Entry point of the aspect.
    public override void BuildAspect(IAspectBuilder<IMethod> builder)
    {
        // 此處必須調用,否則目標方法將不會被覆蓋,因為這裡Override與BuildAspect共同使用了
        base.BuildAspect(builder);

        // 驗證欄位
        var loggerField = builder.Target.DeclaringType.Fields.OfName("_logger").SingleOrDefault();
        if (loggerField == null || !loggerField.Type.Is(typeof(ILogger)) || loggerField.IsStatic)
        {
            // 報告異常
            builder.Diagnostics.Report(_loggerFieldNotFoundError.WithArguments((builder.Target.DeclaringType, builder.Target)), builder.Target.DeclaringType);
            // 不執行Aspect
            builder.SkipAspect();
            return;
        }
    }
    public override dynamic? OverrideMethod()
    {
        meta.This._logger.Info(meta.Target.Method.ToDisplayString() + " 開始運行.");
        var result = meta.Proceed();
        meta.This._logger.Info(meta.Target.Method.ToDisplayString() + " 結束運行.");
        return result;
    }
}

這樣當我們代碼中有錯誤,將會觸發提示。

如果沒有_logger_logger類型不對或為static時則有以下提示
image

同時也可以在Aspect中定義Eligibility,在編譯時檢查Aspect作用的目標是否符合要求。
下麵的代碼加到LogAttribute就會檢查Add方法是否為非static

    public override void BuildEligibility( IEligibilityBuilder<IMethod> builder )
    {
        base.BuildEligibility( builder );
        builder.MustBeNonStatic();
    }

此時若將Add修改為static則會提示

error LAMA0037: The aspect 'Log' cannot be applied to 'Program.Add(int, int)' because 'Program.Add(int, int)' must be non-static.

自定義一個代碼分析:要求當前方法只能在符合規則的命名空間中使用

當一個團隊存在多個項目時,我們會約定這裡的某些項目的命名必須符合某一規則。
例如,當我們構建一個微服務項目時,我們會要求所有的資料庫調用,都發生在指定的命名空間中。
此時我們可以使用一個自定義的Aspect構造一個方法的代碼驗證規則。

下麵這個示例是要求調用函數的命名空間必須符合以.Tests結尾的規則,否則給出警告

using Metalama.Framework.Aspects;
using Metalama.Framework.Code;
using Metalama.Framework.Diagnostics;
using Metalama.Framework.Validation;
namespace LogWithWarning
{
    class ForTestOnlyAttribute : Aspect, IAspect<IDeclaration>
    {
        private static readonly DiagnosticDefinition<IDeclaration> _warning = new(
            "DEMO02",
            Severity.Warning,
            "'{0}' 只能在一個以 '.Tests'結尾的命名空間中使用");

        public void BuildAspect(IAspectBuilder<IDeclaration> builder)
        {
            builder.WithTarget().RegisterReferenceValidator(this.ValidateReference, ReferenceKinds.All);
        }

        private void ValidateReference(in ReferenceValidationContext context)
        {
            if (!context.ReferencingType.Namespace.FullName.EndsWith(".Tests"))
            {
                context.Diagnostics.Report(_warning.WithArguments(context.ReferencedDeclaration));
            }
        }
    }
}

此時當我們在非.Tests結尾的命名空間中調用時。
則會發生如下提示。

image

引用

供大家學習參考,轉文章隨意--重典
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 你好呀,我是歪歪。 我最近在 stackoverflow 上看到一段代碼,怎麼說呢。 就是初看一臉懵逼,看懂直接跪下! 我先帶你看看 stackoverflow 上的這個問題是啥,然後引出這段代碼: https://stackoverflow.com/questions/15182496/why-d ...
  • HashMap是大廠java語言的常考點,主要從底層結構,和線程安全等角度來進行考察,考察點比較集中,但是有一定難度 ...
  • 11月8日Spring官方已經強烈建議使用Spring Authorization Server替換已經過時的Spring Security OAuth2.0,距離Spring Security OAuth2.0結束生命周期還有小半年的時間,是時候做出改變了。目前Spring Authorizati ...
  • 本文主要解決兩個問題 * C# Winform高DPI字體模糊. * 高DPI下(縮放>100%), UI設計器一直提示縮放到100%, 如果不重啟到100%,設計的控制項會亂飛. ...
  • 1、導航查詢特點 作用:主要處理主對象裡面有子對象這種層級關係查詢 1.1 無外鍵開箱就用 其它ORM導航查詢 需要 各種配置或者外鍵,而SqlSugar則開箱就用,無外鍵,只需配置特性和主鍵就能使用 1.2 高性能優 查詢 性能非常強悍 支持大數據分頁導航查詢 3.3 語法超級爽 註意:多級查詢時 ...
  • 前言 在Web 應用程式中,我們經常會遇到這樣的場景,如用戶信息,租戶信息本次的請求過程中都是固定的,我們希望是這種信息在本次請求內,一次賦值,到處使用。本文就來探討一下,如何在.NET Core 下去利用AsyncLocal 實現全局共用變數。 簡介 我們如果需要整個程式共用一個變數,我們僅需將該 ...
  • 此次,iNeuOS工業互聯網操作系統升級主要針對三維(3D)模型線上編輯與應用、數據實時統計。用戶有現成的3D模型可以導入到平臺中,模型部件與數據點進行綁定,實時反饋狀態信息到3D模型中。數據實時統計主要後期應用到線上Excel報表中,快速開發和生成時表報、日報表、月報表和年報表等應用。 ...
  • 從編程開發的角度來簡單來說,CLR就相當於“執行/運行”我們所編寫程式的“環境/服務”。這就好比如我們組裝了一個賽車,我們的賽車需要依賴“跑道”作為一個環境,賽車才能進行飛馳。而這個“跑道”就類似於CLR。在Java平臺中程式員要向一臺電腦部署軟體時,要確保軟體運行,電腦上就要按照JVM(Java虛 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...