日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题

發布時間:2023/12/4 asp.net 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

理想的代碼優化方式

團隊日常協作中,自然而然的會出現很多重復代碼,根據這些代碼的種類,之前可能會以以下方式處理

方式描述應用時可能產生的問題
硬編碼多數新手,或逐漸腐壞的項目會這么干,會直接復制之前實現的代碼帶來的問題顯而易見的多,例如架構會逐漸隨時間被侵蝕,例外越來越多
提取函數提取成為函數,然后復用提取函數,然后復用,會比直接硬編碼好些,但是仍然存在大量因“例外”而導致增加參數、增加函數重載的情況
模板生成器CodeSmith/T4等因為是獨立進程,所以對于讀取用戶代碼或項目,實現難度較高,且需要現有用戶項目先生成成功,再進行生成 ,或者是完全基于新項目
代碼片段VS自帶的代碼片段功能無法對復雜的環境或條件做出響應
AOP框架面向切面編程,可以解決很多于用戶代碼前后增加操作的事情但是大多AOP框架都是基于透明代理形式實現的,對于相互調用較多的代碼,但形成性能壓力,而且因為要符合透明代理的規則,所以要提供相應的子類或接口。

基于Rosyln的編譯時插入代碼

但以上這幾種,AOP算是最理想的方式,但是感覺上還可以有更好的解決方案。

直到讀到了這篇文章?Introducing C# Source Generators,文中提供了一種新的解決方案,即通過Roslyn的Source Generator在編譯時直接讀取當前項目中的語法樹,處理并生成的新代碼,然后在編譯時也使用這些新代碼。

那么如果可以讀取現有代碼的語法樹,通過讀取代碼中的標記,那么在代碼生成過程中是否就能直接生成。
實現如下效果:
項目中的源代碼?Program.cs

internal class Program { [Log] private static int Add( int a, int b ) { return a + b; } }

自動根據?LogAttribute?自動編譯成的代碼?Program.g.cs

internal class Program { [Log] private static int Add( int a, int b ) { Console.WriteLine("Program.Add(int, int) 開始運行."); int result; result = a + b; Console.WriteLine("Program.Add(int, int) 結束運行."); return result; } }

當然LogAttribute中需要去實現插入代碼。
然后項目自動使用新生成的Program.g.cs進行編譯。這樣就實現了基于編譯時的AOP。

即實現以下流程

使用Metalama實現以上流程

經過尋找,發現其實已經有框架可以實現我上面說的流程了,也就是在編譯時實現代碼的插入。
https://www.postsharp.net/metalama 。

下面作一個簡單示例

  • 創建一個.NET6.0的控制臺應用,我這里命名為LogDemo,
    其中的入口文件Program.cs

  • namespace LogDemo { public class Program { public static void Main(string[] args) { var r = Add(1, 2); Console.WriteLine(r); } // 這里寫一個簡單的方法,一會對這個方法進行代碼的插入 private static int Add(int a, int b) { var result = a + b; Console.WriteLine("Add" + result); return result; } } }
  • 在項目中使用Metalama

  • 通過引用包?https://www.nuget.org/packages/Metalama.Framework, 注意Metalama當前是Preview版本,如果通過可視化Nuget管理器引入,需要注意勾選包含預發行版

    dotnet add package Metalama.Framework --version 0.5.7-preview
  • 編寫一個AOP的Attribute

  • 在項目中引入?Metalama.Framework后無需多余配置或代碼,直接編寫一個AOP的Attribute

    using Metalama.Framework.Aspects;namespace LogDemo { public class Program { public static void Main(string[] args) { var r = Add(1, 2); Console.WriteLine(r); } // 在這個方法中使用了下面的Attribute [LogAttribute] private static int Add(int a, int b) { var result = a + b; Console.WriteLine("Add" + result); return result; } } // 這里是增加的 Attribute public class LogAttribute : OverrideMethodAspect { public override dynamic? OverrideMethod() { Console.WriteLine(meta.Target.Method.ToDisplayString() + " 開始運行."); var result = meta.Proceed(); Console.WriteLine(meta.Target.Method.ToDisplayString() + " 結束運行."); return result;} } }
  • 執行結果如下

  • Program.Add(int, int) 開始運行. Add3 Program.Add(int, int) 結束運行. 3
  • 生成的程序集進行反編譯,得到的代碼如下:

  • using Metalama.Framework.Aspects; namespace LogDemo { public class Program { public static void Main(string[] args) { var r = Add(1, 2); Console.WriteLine(r); } // 在這個方法中使用了下面的Attribute [LogAttribute] private static int Add(int a, int b) { Console.WriteLine("Program.Add(int, int) 開始運行."); int result_1; var result = a + b; Console.WriteLine("Add" + result); result_1 = result; Console.WriteLine("Program.Add(int, int) 結束運行."); return result_1; } } #pragma warning disable CS0067 // 這里是增加的 Attribute public class LogAttribute : OverrideMethodAspect { public override dynamic? OverrideMethod() => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time."); } #pragma warning restore CS0067 }

    總結

    這樣就完全實現了我之前想要的效果,當然使用Metalama還可以實現很多能極大地提高生產力的功能,它不僅可以對方法進行改寫,也可以對屬性、字段、事件、甚至是類、命名空間進行一些操作 。

    引用

    Introducing C# Source Generators:https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/
    Metalama官網:https://www.postsharp.net/metalama

    總結

    以上是生活随笔為你收集整理的使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。