本篇只介紹 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
When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.
評論