本篇只介紹 Microsoft 所提供的套件來處理動態執行 Expression,後面幾篇會陸續介紹其他第三方開源套件
初次執行時需要花費一些時間編譯,因此有效能要求的需求的話,不建議使用
優點:
缺點:
評價:★★★★
Install-Package Microsoft.CodeAnalysis.CSharp.Scripting
using Microsoft.CodeAnalysis.CSharp.Scripting; using Microsoft.CodeAnalysis.Scripting; using System; using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; public static class ExpressionEvaluator { public static async Task<object> EvalAsync(string expression, object data = null) { // 設定 import 和 reference var imports = new List<string> { "System", "System.Math", "System.Linq", "System.Text", "System.Text.RegularExpressions", "System.Collections", "System.Collections.Generic" }; var references = new List<Assembly> { typeof(Match).Assembly, typeof(Regex).Assembly }; var options = ScriptOptions.Default .WithReferences(references) .WithImports(imports) .WithAllowUnsafe(false); // 執行 Expression var result = await CSharpScript.EvaluateAsync(expression, options); } }
要使用的 Namespace 和類別參考 (Reference)都在 Step.1 初始化時設定
// result: "2021-04-06 10:00:00" object dateResult = await ExpressionEvaluator.EvalAsync("DateTime.Now.ToString(\"yyyy-MM-dd HH:mm:ss\")"); // result: 178.53981633974485 object mathResult = await ExpressionEvaluator.EvalAsync("(5 * 5 * PI) + 100"); // result: "te" object textResult = await ExpressionEvaluator.EvalAsync("\"testsplit\".Split('s')[0]");
為 Microsoft Bot Builder 底下的一個模組套件,而 Adaptive Card 也使用這個套件來資料綁定
Adaptive Expression 的程式語言並非 C#、JavaScript...任何一種,而是以類似 Excel Function Expression 的程式語言
除了有提供 C# 版本外,還有提供 JavaScript 的版本
優點:
缺點:
評價:★★★★★
Install-Package AdaptiveExpressions
● Adaptive Expression 有提供內建的 Function 可以使用,詳細請至 Adaptive Expressions Prebuilt Functions 微軟官方文件查看
● 如果內建的 Function 無法滿足時,可以自行加入自訂 Function
using AdaptiveExpressions; using System; public static class ExpressionEvaluator { public static object Eval(string expression, object data = null) { try { // 剖析 Expression var adpExpression = Expression.Parse(expression); // 加入自訂 Function (Optional) AddCustomFunction(); // 執行 Expression var (value, error) = adpExpression.TryEvaluate(data); if (error == null && value != null) { // 執行成功 return value; } // 執行失敗 return expression; } catch { // 執行失敗 return expression; } } // 加入自訂 Function public static void AddCustomFunction() { // 清除 Functions (避免重複註冊) Expression.Functions.Clear(); // 加入自訂 Function,需包含 Function Name 和 Function 實作 Expression.Functions.Add("localNow", (args) => { // 取得 Function 參數 string format = "yyyy-MM-ddTHH:mm:ss.fffZ"; if (args != null && args.Count > 0 && args[0] != null) { format = Convert.ToString(args[0]); } return DateTime.Now.ToString(format); }); } }
可以傳入一個物件 (Object) 提供 Expression 執行時使用
// result: "2021-04-06 10:00:00" object dateResult = ExpressionEvaluator.Eval("addHours(utcNow(), 8, 'yyyy-MM-dd HH:mm:ss')"); // result: 178.53981633974485 object mathResult = ExpressionEvaluator.Eval("(5 * 5 * PI) + 100", new { PI = Math.PI }); // result: [ "Hello", "World!" ] object textResults = ExpressionEvaluator.Eval("split(Text, ' ')", new { Text = "Hello World!" }); // result: "張三丰 (武當派掌門人)" var data = new { Name = "張三丰", Detial = new { Description = "武當派掌門人" } }; object stringResults = ExpressionEvaluator.Eval("concat(Name, ' (', Detial.Description, ')')", data); // 使用自訂 Function ─ localNow('{format}') // result: "2021-04-06 10:00:00" object customResult = ExpressionEvaluator.Eval("localNow('yyyy-MM-dd HH:mm:ss')");
只能處理簡單的數學計算處理,如果需要更複雜的的處理,請考慮別的套件
優點:
缺點:
評價:★★★
// result: 2 int intResult = Convert.ToInt32(new DataTable().Compute("1 + 1", string.Empty)); // result: true bool boolResult = Convert.ToBoolean(new DataTable().Compute("1 = 1", string.Empty));
除了上述的3種做法,還有以下5種做法,但是因為我沒有深入研究,有興趣者請自行研究
WebBrowser.Document.InvokeScript