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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

使用Roslyn脚本化C#代码,C#动态脚本实现方案

發(fā)布時間:2023/12/4 C# 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用Roslyn脚本化C#代码,C#动态脚本实现方案 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

來源:https://www.cnblogs.com/7tiny/p/10279349.html

【前言】

  Roslyn 是微軟公司開源的 .NET 編譯器。

  編譯器支持 C# 和 Visual Basic 代碼編譯,并提供豐富的代碼分析 API。

  Roslyn不僅僅可以直接編譯輸出,難能可貴的就是上述描述中的開放了編譯的API,使得代碼腳本化成為了可能。

  關(guān)于Roslyn,本文不做過多介紹,因?yàn)樵俳榻B的豐滿終究不及官方文檔介紹的細(xì)膩,各位請移步官方說明地址:https://github.com/dotnet/roslyn/wiki

  

  眾所周知,我們實(shí)現(xiàn)的Filter往往是寫死的代碼在項(xiàng)目里面的,一經(jīng)發(fā)布,便不能隨時改動,有過Paas平臺開發(fā)經(jīng)驗(yàn)的同僚更能體會到租戶靈活配置個性化需求是一個難點(diǎn)。

  那么,我們怎么能針對不同的業(yè)務(wù)邏輯靈活地在已經(jīng)部署好地站點(diǎn)上制定不同地業(yè)務(wù)邏輯呢,讓我們一起走進(jìn)這個世界。

  本文將通過一個小Demo的實(shí)現(xiàn)講述如何使用Roslyn腳本化代碼,以及如何采用腳本化的代碼對一個網(wǎng)站接口實(shí)現(xiàn)腳本控制Before和After過濾器的功效。

  Demo 源碼地址:https://github.com/sevenTiny/Demo.CSharpScript

一、熟悉Roslyn API

  • 首先項(xiàng)目中引入微軟腳本API相關(guān)的Nuget包

  按順序引入下面三個Nuget包

  Microsoft.CodeAnalysis.CSharp   

  Microsoft.CodeAnalysis.Scripting 

  Microsoft.CodeAnalysis.CSharp.Scripting

  • 了解API

  1.我們寫一個Run腳本的Demo:

[Fact] [Trait("desc", "調(diào)用動態(tài)創(chuàng)建的腳本方法")]public void CallScriptFromText() { ? ?string code1 = @"public class ScriptedClass{public string HelloWorld { get; set; }public ScriptedClass(){HelloWorld = ""Hello Roslyn!"";}}"; ? ?var script = CSharpScript.RunAsync(code1).Result; ? ?var result = script.ContinueWithAsync<string>("new ScriptedClass().HelloWorld").Result;Assert.Equal("Hello Roslyn!", result.ReturnValue); }

  Demo中,我們用字符串定義了一個類,并在其中寫了小段邏輯,通過Run方法和ContinueWityAsync方法分別執(zhí)行了兩段腳本,最終的結(jié)果輸出了:

 "Hello Roslyn!"

  2.我們再寫一個腳本調(diào)用已存在的類的Demo:

  首先我們定義一個類型:

public class TestClass { ? ?public string arg1 { get; set; } ? ?public string GetString(){ ? ? ? ?return "hello world!";} ? ?public string DealString(string a){ ? ? ? ?return a;} }

  然后寫腳本執(zhí)行該類型里面的DealString方法(帶參數(shù)和返回值的)

[Trait("desc", "使用類的實(shí)例調(diào)用類的帶參數(shù)的方法,并獲取返回值")] [Theory] [InlineData("123")]public void CallScriptFromAssemblyWithArgument(string x) { ? ?var script = CSharpScript.Create<string>("return new TestClass().DealString(arg1);",ScriptOptions.Default.WithReferences(typeof(TestClass).Assembly).WithImports("Test.Standard.DynamicScript"), globalsType: typeof(TestClass));script.Compile(); ? ?var result = script.RunAsync(new TestClass { arg1 = x }).Result.ReturnValue;Assert.Equal(x, result.ToString()); }

  RunAsync 方法傳遞參數(shù),參數(shù)名必須要和參數(shù)類型的字段名稱一直才可以識別

  ScriptOptions.Default.WithReferences 明確程序集要引用的類型,類似于引用一個dll

  ScriptOptions.Default.WithImports 明確代碼中引用的類型,類似于using

  globalsType: typeof(TestClass) 指定了傳遞參數(shù)需要用到的類型(API不支持隱式的參數(shù),只能定義一個明確類型傳遞參數(shù))

  script.Compile(); 方法將腳本編譯并保存到內(nèi)存中,待調(diào)用

  script.RunAsync(new TestClass { arg1 = x }).Result.ReturnValue 調(diào)用腳本并傳遞參數(shù)獲取返回值,x=“123”,單元測試傳遞的參數(shù)

  然后我們便得到了“123”的返回值

  • 更多API

  更多的API我們可以從官方介紹文檔中輕松得到

  官方WIKI:https://github.com/dotnet/roslyn/wiki/Scripting-API-Samples

  

二、一個MVC Action Before/After Filter(Action執(zhí)行前后過濾器)的Demo

  首先說明項(xiàng)目背景及功能

  • 運(yùn)行.netcore mvc站點(diǎn),點(diǎn)擊菜單欄的進(jìn)入Demo便得到下面界面

  • 我們定義了一個Action,按序號創(chuàng)建了100條記錄用于數(shù)據(jù)演示

  • before 腳本的name參數(shù)是從url獲取到的name參數(shù),返回結(jié)果將作為100條Demo數(shù)據(jù)的“Name”字段Contains方法的參數(shù) 相當(dāng)于Linq .Where(t=>t.Name.Contains(name));

  • after 腳本是將 Where 語句過濾后的結(jié)果集作為參數(shù),然后執(zhí)行完腳本中的代碼后,返回結(jié)果展示在了下面的頁面上

  • 可以簡單理解為before是校驗(yàn)url參數(shù)的,after是二次處理結(jié)果數(shù)據(jù)的

  • 為了方便測試,我們的腳本都是從本地文件讀寫的

  •   Demo的管道形式的數(shù)據(jù)流如下:

      

      Demo界面:

      

    ?  我們從代碼中可以看到上述描述的數(shù)據(jù)流程:

      

      ss是執(zhí)行文件保存的Before腳本后的結(jié)果

      然后我們把他當(dāng)作校驗(yàn)Name的參數(shù)

      result是data數(shù)據(jù)執(zhí)行After腳本之后的結(jié)果,然后我們將最終的結(jié)果返回到界面

      測試Demo的提供:

    using System.Collections.Generic;namespace Demo.CSharpScript.Models { ? ?/// <summary>/// 測試實(shí)體 ? ?/// </summary>public class DemoModel{ ? ? ? ?public int ID { get; set; } ? ? ? ?public int Age { get; set; } ? ? ? ?public string Name { get; set; } ? ? ? ?public string Desc { get; set; } ? ? ? ?/// <summary>/// 測試數(shù)據(jù) ? ? ? ?/// </summary>/// <returns></returns>public static List<DemoModel> GetDemoDatas(){ ? ? ? ? ? ?var list = new List<DemoModel>(); ? ? ? ? ? ?for (int i = 0; i < 100; i++){list.Add(new DemoModel { ID = i, Age = i, Name = $"7tiny_{i}", Desc = $"第{i}條測試數(shù)據(jù)" });} ? ? ? ? ? ?return list;}} }

      下面我們來看看兩處執(zhí)行腳本的地方

      首先是Before處理邏輯:

      

      拼接了一個腳本(中間部分從文件讀取),使用Roslyn API進(jìn)行動態(tài)編譯執(zhí)行,然后將執(zhí)行的結(jié)果返回

      然后是After處理邏輯:

      

      同樣是拼接了一個腳本(中間部分從文件讀取),使用Roslyn API進(jìn)行動態(tài)編譯執(zhí)行,然后將執(zhí)行的結(jié)果返回

      在上述過程中還將多個命名空間引入,以便在After腳本中寫Linq語法,否則會執(zhí)行失敗,出現(xiàn)異常

      語法我們在上述章節(jié)都已經(jīng)演示過了

      實(shí)際我們的腳本:

      

      before中直接忽略了參數(shù)返回了字符串“1”,然后我們Action代碼首先過濾的數(shù)據(jù)就剩下Name字段包含“1”的

      after中再次使用Where語法,過濾剩下數(shù)據(jù)中Name字段包含“3”的

      那么,我們的結(jié)果中只剩下兩條符合條件:

      

      拓展一下

      

      我們的測試到此本也結(jié)束了,但是為了我們測試腳本更加方便,我這里提供了一個微軟剛出的工具,try.dot.net

      不了解的同學(xué)可以參考之前博文熟悉一下 try.dot.net :https://www.cnblogs.com/7tiny/p/10277600.html

      我們可以在測試站點(diǎn)上點(diǎn)“點(diǎn)我?guī)椭銓懩_本”的菜單:

      

      然后進(jìn)入try.dot.net的界面:

      

      在這里我們可以使用智能提示編寫腳本,寫完后粘貼回測試的頁面,避免文本框?qū)懘a出現(xiàn)錯誤

    三、開拓視野

      我們今天用的是 Roslyn,事實(shí)上,微軟有很多類庫可以幫助我們執(zhí)行動態(tài)腳本代碼,例如:

      CodeDom(動態(tài)生成或編譯代碼)

      ClearScript(執(zhí)行javascript腳本和CSharp代碼)  https://microsoft.github.io/ClearScript/Examples/Examples.html

      PhpNet(執(zhí)行Php代碼)

      JavaDynamicCompiler(執(zhí)行Java代碼)

      IronPython

      ...

      有興趣可以去搜索拓展一下!謝謝~

      最后,本文Demo 源碼地址:https://github.com/sevenTiny/Demo.CSharpScript

    原文地址:https://www.cnblogs.com/7tiny/p/10279349.html


    .NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com

    點(diǎn)個贊,讓我在心里記住你???

    總結(jié)

    以上是生活随笔為你收集整理的使用Roslyn脚本化C#代码,C#动态脚本实现方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。