.NET靜態代碼織入——肉夾饃(Rougamo) 發布1.1.0

肉夾饃是什么

肉夾饃(https://github.com/inversionhourglass/Rougamo)通過靜態代碼織入方式實現AOP的組件。.NET常用的AOP有Castle DynamicProxy、AspectCore等,以上兩種AOP組件都是通過運行時生成一個代理類執行AOP代碼的,肉夾饃則是在代碼編譯時直接修改原始方法IL代碼,在原始方法內織入AOP代碼的。.NET靜態AOP的組件或許有人使用過PostSharp,這是一個功能完善且強大的靜態代碼織入組件,Postsharp有社區版,但可惜的是社區版不支持異步方法,肉夾饃的實現方式與Postsharp類似,同時也支持了異步方法,如果你僅僅使用了Postsharp方法層級的AOP代碼織入功能,可以嘗試使用肉夾饃來替代Postsharp。

在?上一篇文章?中介紹了1.0.0版本肉夾饃的功能,1.0.0版本能夠進行的AOP操作主要是日志記錄以及APM操作,給出的示例項目也是OpenTelemetry的APM項目。在上一篇文章的評論以及github issue中都有朋友詢問是否能處理異常以及修改返回值等操作,最終拖了較長一段時間于近期發布了1.1.0版本實現了這些功能。

快速開始

# 添加NuGet引用dotnet add package Rougamo.Fody
public class TestService{[Fact]    public async void Test1(){        var v1 = await M1();Assert.Null(v1);        var v2 = Sum(1, null);Assert.Equal(-1, v2);        var v3 = await M2();Assert.Empty(v3);}[MuteException]    public async Task<string> M1(){        throw new NotImplementedException();}[ArgNullCheck]    public int Sum(int? a, int? b){        return a.Value + b.Value;}[ReturnNullCheck]    public async Task<string> M2(){        await Task.Yield();        return null;}
}public class MuteExceptionAttribute : MoAttribute{    public override void OnException(MethodContext context){        if (context.RealReturnType == typeof(string)){context.HandledException(this, null);}}
}public class ArgNullCheckAttribute : MoAttribute{    public override void OnEntry(MethodContext context){        foreach (var arg in context.Arguments){            if (arg == null){context.ReplaceReturnValue(this, -1);}}}
}public class ReturnNullCheckAttribute : MoAttribute{    public override void OnSuccess(MethodContext context){        if (context.ReturnValue == null){context.ReplaceReturnValue(this, string.Empty);}}
}折疊

在上面的示例代碼中MuteExceptionAttribute重寫了OnException通過MethodContext.HandledException表明異常已處理并將返回值設置為null
ArgNullCheckAttribute重寫了OnEntry通過MethodContext.ReplaceReturnValue設置了返回值,由于OnEntry是在執行方法前調用,這種方式會在OnEntry執行完畢之后直接將ReplaceReturnValue設置的返回值作為方法的返回值直接返回,一般參數驗證、緩存邏輯會用到;
ReturnNullCheckAttribute重寫了OnSuccess通過MethodContext.ReplaceReturnValue修改了實際的返回值,示例中通過這種方式避免返回null值。

注意事項

  • 如果方法是async Task那么MethodContext.RealReturnType取值為typeof(void),如果是async Task<T>那么取值為typeof(T),但如果返回值為TaskTask<T>但并沒有使用async寫法,那么其值就是typeof(Task)typeof(Task<T>),這樣設定的好處是,你設置的返回值類型與該屬性的值相同即可,不用考慮方法是否異步

  • 不論是異常處理還是設置/修改返回值,設置的返回值類型必須與方法定義的返回類型(MethodContext.RealReturnType)相同,類型不同時運行時會報錯

  • OnExit中調用MethodContext.ReplaceReturnValue無法修改返回值

補充說明

在?上一篇文章?中由于是第一篇文章,介紹的東西較多,部分功能并沒有在文章中詳細說明,本篇由于篇幅較短,所以會補上一些說明,不過這里也不會介紹全部的,詳細的介紹可以移步 github(https://github.com/inversionhourglass/Rougamo)

Iterator / AsyncIterator 不支持修改返回值和異常處理

IteratorAsyncIterator也就是下面的寫法

public IEnumerable<int> Iterator(int count){    yield return 1;    yield return 2;    yield return 3;
}public async IAsyncEnumerable<int> AsyncIterator(int count){    yield return 3;    await Task.Yield();    yield return 2;    await Task.Yield();    yield return 1;
}

之所以不支持,是因為它們并不直接返回一個集合,而是返回一個狀態機(StateMachine),使用foreach迭代時實際每次迭代執行狀態機的MoveNext方法獲取本次迭代的返回值,考慮到實現這種特殊機制的復雜性以及平時使用的頻率,當前對此種類型不進行支持。

Iterator / AsyncIterator 不支持記錄返回值

同樣的,IteratorAsyncIterator默認也無法通過MethodContext.ReturnValue獲取方法的返回值,但可以通過FodyWeavers.xmlRougamo節點增加屬性配置enumerable-returns="true"來記錄IteratorAsyncIterator的返回值到MethodContext.ReturnValue

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"><Rougamo enumerable-returns="true" /></Weavers>

這個設定是因為狀態機并沒有保存所有的元素到一個集合中,每個元素都是一次一次調用MoveNext執行代碼返回的,如果你使用foreach遍歷IteratorAsyncIterator,并且對每次遍歷的元素使用玩之后并沒有進行保存,那么上一個元素可能在你遍歷下一個元素時被GC回收。記錄它們的返回值的實現方式是額外建立一個集合保存每次迭代的元素值,這種方式對上面說的的foreach遍歷的情況來說會產生額外的內存消耗,而如果迭代器的元素很多,或者每個元素本身很占內存,那么這種方式可能會額外占用大量內存空間,所以開啟這個開關前需要考慮一番。

最后

如果在使用肉夾饃的過程中遇到了什么問題,或者希望增加一些什么樣的功能,歡迎到github(https://github.com/inversionhourglass/Rougamo)里提issue,不過對于新功能,可能會有一個較長的周期才能完成并發布正式版。
隨著SourceGenerator的應用越來越廣泛,Mono.Cecil的應用場景被進一步壓縮,一開始提到的動態代理現在也能通過SourceGenerator在編譯時生成代理類,這是一件好事,相比晦澀易錯的IL,SourceGenerator提供的語法樹更加方便易懂且不易出錯,但這并不代表Mono.Cecil應該退場了(至少現在不是),Mono.Cecil雖然門檻高,但他的功能也同樣強大,直接修改IL是SourceGenerator和`Emit所無法做到的(至少現在是這樣),如果在以后的編程之路中遇到了SourceGenerator和`Emit無法解決的問題,希望你能想起還有Mono.CecilFody這條路,如果有時間可以嘗試一下,也希望肉夾饃這個項目能給你帶來一些參考價值。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284097.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284097.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284097.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Msys2 國內源(2017.3.30)

確定可用&#xff01; Server https://mirrors.tuna.tsinghua.edu.cn/msys2/msys/$arch轉載于:https://www.cnblogs.com/baud/p/6644887.html

基于 IdentityServer3 實現 OAuth 2.0 授權服務【密碼模式(Resource Owner Password Credentials)】...

密碼模式&#xff08;Resource Owner Password Credentials Grant&#xff09;中&#xff0c;用戶向客戶端提供自己的用戶名和密碼。客戶端使用這些信息&#xff0c;向"服務商提供商"索要授權。基于之前的 IdentityServer3 實現 OAuth 2.0 授權服務【客戶端模式(Clie…

【GlobalMapper精品教程】035:用CASS自帶數據創建高程地形、等高線教程

本文講述globalmapper用CASS自帶數據創建高程地形、等高線教程。 文章目錄 1. 坐標生成點2. 點轉高程格網3. 生成等高線4. 保存等高線CASS自帶等高線數據dgx.dat預覽:包含點號、編碼、東坐標、北坐標、高程5列,可以不用做任何修改,在Globalmapper中生成點。 1. 坐標生成點 …

SaaS產品的免費試用到底該怎么做

”SaaS產品的免費試用&#xff0c;絕不僅僅只是開放產品試用期這么簡單&#xff0c;很多企業并沒有重視免費試用模式的搭建和轉化路徑“ 很多SaaS廠商的產品都會提供免費試用的機會&#xff0c;雖然試用的最終目標是促成用戶為產品價值付費&#xff0c;但是很多SaaS廠商在開放系…

【.NET6+WPF】WPF使用prism框架+Unity IOC容器實現MVVM雙向綁定和依賴注入

前言&#xff1a;在C/S架構上&#xff0c;WPF無疑已經是“桌面一霸”了。在.NET生態環境中&#xff0c;很多小伙伴還在使用Winform開發C/S架構的桌面應用。但是WPF也有很多年的歷史了&#xff0c;并且基于MVVM的開發模式&#xff0c;受到了很多開發者的喜愛。并且隨著工業化的進…

sql 中 limit 與 limit,offset連用的區別

① select * from table limit 2,1; #跳過2條取出1條數據&#xff0c;limit后面是從第2條開始讀&#xff0c;讀取1條信息&#xff0c;即讀取第3條數據 ② select * from table limit 2 offset 1; #從第1條&#xff08;不包括&#xff09;數據開始取出2條…

【ArcGIS Pro微課1000例】0022:基于DEM進行流域分析生成流域圖

文章目錄 一、填洼二、流向分析三、計算流域一、填洼 填洼Fill,在進行水文分析后續操作前,首先要對DEM進行填洼,創建無凹陷點的DEM。 填洼需要使用水文分析工具下的【填洼】。 確定輸入與輸出即可。 填洼結果: 二、流向分析 在ArcGIS中使用的是八方向流量建模(D8算法),工…

Spring配置文件中bean標簽的scope屬性

轉自&#xff1a;https://fj-sh-chz.iteye.com/blog/1775149 singleton &#xff08;默認屬性&#xff09; Spring將Bean放入Spring IOC容器的緩存池中&#xff0c;并將Bean引用返回給調用者&#xff0c;spring IOC繼續對這些Bean進行后續的生命管理。BeanFactory只管理一個共…

[轉]Druid概述

目錄 1.Apache Druid簡介 2.Apache Druid架構 2.1 服務器類型 2.1.1 Master Server 2.1.2 Query 2.1.3 Data Server 2.2 外部依賴 2.2.1 Deep Storage 2.2.2 Metadata Storage 2.2.3 Zookeeper 2.3 存儲設計 3.在HDP上安裝Apache Druid 3.1 準備數據庫 3.2 安裝…

在 .NET MAUI 中如何更好地自定義控件

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;10分鐘)今天&#xff0c;我想談談并向您展示在.NET MAUI中完全自定義控件的方法。在查看 .NET MAUI 之前&#xff0c;讓我們回到幾年前&#xff0c;回到 Xamarin.Forms 時代。那時&#xff0c;我們有很多自定義控件的…

【GlobalMapper精品教程】036:基于DEM的流域計算生成流域圖

Globalmapper基于DEM的流域計算生成流域圖教程。 文章目錄一、加載DEM二、流域分析一、加載DEM 加載配套實驗數據。 二、流域分析 GM中的流域分析工具位于分析→生成流域&#xff0c;如下所示&#xff1a; 參數設置如下&#xff1a; 流域計算結果&#xff1a;

html之file標簽 --- 圖片上傳前預覽 -- FileReader

記得以前做網站時&#xff0c;曾經需要實現一個圖片上傳到服務器前&#xff0c;先預覽的功能。當時用html的<input type"file"/>標簽一直實現不了&#xff0c;最后舍棄了這個標簽&#xff0c;使用了其他方式來實現了這個功能。 今天無意發現了一個知識點&#…

Android Studio3.0簡介

Android Studio 3.0.0 Android Studio 3.0.0 (2017年10月)是一個主要版本&#xff0c;包括各種新功能和改進 Android插件的Gradle 3.0.0 ? 支持Android 8.0 ? 支持Java 8庫和Java 8語言功能&#xff08;沒有Jack編譯器&#xff09; ? 支持Android測試支持庫1.0&#xff08;A…

嵌入式linux面試題解析(二)——C語言部分三

嵌入式linux面試題解析&#xff08;二&#xff09;——C語言部分三1、下面的程序會出現什么結果#include <stdio.h>#include <stdlib.h>#include <string.h>void getmemory(char *p){ p(char *) malloc(100); strcpy(p,”hello world”);}int main( ){…

什么是JavaBean、Bean? 什么是POJO、PO、DTO、VO、BO ? 什么是EJB、EntityBean?

前言&#xff1a; 在Java開發中經常遇到這些概念問題&#xff0c;有的可能理解混淆&#xff0c;有的可能理解不到位&#xff0c;特此花了很多時間理順了這些概念。不過有些概念實際開發中并沒有使用到&#xff0c;可能理解還不夠準確&#xff0c;只能靠后續不斷糾正了。 1、什么…

【GlobalMapper精品教程】037:構建泰森多邊形(Thiessen Polygon)實例精解

泰森多邊形是進行快速插值和分析地理實體影響區域的常用工具。例如,用離散點的性質描述多邊形區域的性質,用離散點的數據計算泰森多邊形區域的數據。泰森多邊形可用于定性分析、統計分析和臨近分析等。 文章目錄 一、泰森多邊形的概念二、泰森多邊形的特點三、泰森多邊形構建…

WPF 實現 Gitee 泡泡菜單「完」

WPF 實現 Gitee 泡泡菜單「完」氣泡菜單「完」作者&#xff1a;WPFDevelopersOrg原文鏈接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用大于等于.NET40&#xff1b;Visual Studio 2022;項目使用 MIT 開源許可協議&#xff1b;需要實現泡泡菜單需…

BZOJ 4516: [Sdoi2016]生成魔咒 [后綴自動機]

4516: [Sdoi2016]生成魔咒 題意&#xff1a;詢問一個字符串每個前綴有多少不同的子串 做了一下SDOI2016R1D2&#xff0c;題好水啊隨便AK 強行開map上SAM 每個狀態的貢獻就是\(Max(s)-Min(s)1\) 插入的時候維護一下就行了 #include <iostream> #include <cstdio> #i…

Fiddler抓包5-接口測試(Composer)

前言 Fiddler最大的優勢在于抓包&#xff0c;我們大部分使用的功能也在抓包的功能上&#xff0c;fiddler做接口測試也是非常方便的。 對應沒有接口測試文檔的時候&#xff0c;可以直接抓完包后&#xff0c;copy請求參數&#xff0c;修改下就可以了。 一、Composer簡介 點開右側…

【GlobalMapper精品教程】038:模擬水位上升(洪水淹沒分析)案例教程

基于數字高程模型 ( DEM )格網模型,實現給定水深情況下洪水淹沒區的計算模型,討論洪水淹沒演進過程可視化實現的關鍵技術,以三維可視化方式,動態而形象地模擬在指定洪水水位下的洪水淹沒演進過程。 文章目錄 一、洪水淹沒效果二、洪水淹沒實現三、查詢淹沒區域面積參考教程…