一、简介
Dynamic Expresso是一个用.NET Standard 2.0编写的简单c#语句的解释器。 Dynamic Expresso嵌入了自己的解析逻辑,通过将其转换为.NET lambda表达式或委托来解释c#语句。
使用Dynamic Expresso开发人员可以创建可编写脚本的应用程序,无需编译即可执行.NET代码,或者创建动态linq语句。
语句是使用c#语言规范的子集编写的。 全局变量或参数可以被注入并在表达式中使用。 它不会生成程序集,但会动态地创建表达式树。
二、安装
新建控制台项目DynamicExpressoResearch,并通过NUGet添加DynamicExpresso.Core;
三、功能和特性
-
返回值
你可以解析并执行一个void类型没有返回值的表达式,或者也可以返回任何有效的.NET类型。我们可以在解析表达式的时候指定期望的返回类型。
static void EvalVoidExp()
{
var target = new Interpreter();
var t = target.Eval("Program.empty()", new Parameter("Program", typeof(Program), new Program()));
if (t == null)
{
Console.WriteLine("EvalVoidExp return value is null");
}
}
//EvalVoidExp return value is null
static void EvalSpecReturnTypeExp()
{
var target = new Interpreter();
double result = target.Eval<double>("Math.Pow(x, y) + 5",
new Parameter("x", typeof(double), 10),
new Parameter("y", typeof(double), 2));
Console.WriteLine(string.Format("We specify the return value type of the expression as double, return value is {0}, value type is {1}", result, result.GetType().FullName));
int r = target.Eval<int>("Math.Pow(x, y) + 5",
new Parameter("x", typeof(int), 10),
new Parameter("y", typeof(int), 2));
Console.WriteLine(string.Format("We specify the return value type of the expression as int, return value is {0}, value type is {1}", r, r.GetType().FullName));
}
//We specify the return value type of the expression as double, return value is 105, value type is System.Double
//We specify the return value type of the expression as int, return value is 105, value type is System.Int32
同时内置的表达式parser也可以自动感知表达式的返回类型;
static void AutoInferDataType()
{
var target = new Interpreter();
object r = target.Eval("Math.Pow(x, y) + 5",
new Parameter("x", typeof(int), 10),
new Parameter("y", typeof(int), 2));
Console.WriteLine(string.Format("We do not specify the return value type of the expression, return value is {0}, value type is {1}", r, r.GetType().FullName));
}
2.变量(Variables)
变量依附在Interpreter上,相当于一个全局的控制参数,可以应用到同一个Interpreter实例的所有表达式中;
Interpreter提供了不同的方法可以实现传入不同类型的变量;
SetVariable可以内置的原始类型及复杂的自定义数据类型;
static void SetParameter()
{
var target = new Interpreter();
target.SetVariable("rate", 0.8);
object r = target.Eval("price * rate",
new Parameter("price", typeof(int), 200));
Console.WriteLine(string.Format("The price of 200 with a 20% discount is {0}", r));
r = target.Eval("price * rate",
new Parameter("price", typeof(int), 499));
Console.WriteLine(string.Format("The price of 499 with a 20% discount is {0}", r));
}
The price of 200 with a 20% discount is 160
The price of 499 with a 20% discount is 399.2
SetFunction可以通过委托的方式传递函数
static void SetFunction()
{
var target = new Interpreter();
Func<double, double, double> pow = (x, y) => Math.Pow(x, y);
target.SetFunction("pow", pow);
object r = target.Eval("pow(x, y)",
new Parameter("x", typeof(int), 10),
new Parameter("y", typeof(int), 2));
Console.WriteLine(string.Format("10 to the second power is {0}", r));
r = target.Eval("pow(x, y)",
new Parameter("x", typeof(int), 2),
new Parameter("y", typeof(int), 4));
Console.WriteLine(string.Format("2 to the fourth power is {0}", r));
}
//10 to the second power is 100
//2 to the fourth power is 16
SetExpression可以设置自定义的Expression
static void SetExpression()
{
var target = new Interpreter();
var rateExp = Expression.Constant(0.8);
target.SetExpression("rate", rateExp);
object r = target.Eval("price * rate",
new Parameter("price", typeof(int), 200));
Console.WriteLine(string.Format("The price of 200 with a 20% discount is {0}", r));
r = target.Eval("price * rate",
new Parameter("price", typeof(int), 499));
Console.WriteLine(string.Format("The price of 499 with a 20% discount is {0}", r));
}
3.参数(Parameters)
参数需要每次执行的时候传递,参数可以是任意的类型,我们可以只解析一次表达式,并通过不同的参数进行多次调用;
static void Invoke()
{
var target = new Interpreter();
var parameters = new[] {
new Parameter("x", typeof(int)),
new Parameter("y", typeof(int))
};
var myFunc = target.Parse("x + y", parameters);
myFunc.Invoke(23, 7);
myFunc.Invoke(32, -2);
}
4.内置类型和自定义类型
默认内部直接支持的数据类型有
Object object
Boolean bool
Char char
String string
SByte Byte byte
Int16 UInt16 Int32 int UInt32 Int64 long UInt64
Single Double double Decimal decimal
DateTime TimeSpan
Guid
Math Convert
我们可以直接使用Interpreter.Reference来引用任何的.net类型
static void ReferenceType()
{
var target = new Interpreter().Reference(typeof(Uri));
Console.WriteLine((target.Eval("typeof(Uri)") as Type).FullName);
Console.WriteLine(target.Eval("Uri.UriSchemeHttp"));
}
//System.Uri
//http
5.生成动态委托
我们可以直接使用Interpreter.ParseAsDelegate<TDelegate>来解析表达式生成对应的委托,然后可以直接调用对应的委托。
class Customer
{
public string Name { get; set; }
public int Age { get; set; }
public char Gender { get; set; }
}
static void DynamicDelegate()
{
var customers = new List<Customer> {
new Customer() { Name = "David", Age = 31, Gender = 'M' },
new Customer() { Name = "Mary", Age = 29, Gender = 'F' },
new Customer() { Name = "Jack", Age = 2, Gender = 'M' },
new Customer() { Name = "Marta", Age = 1, Gender = 'F' },
new Customer() { Name = "Moses", Age = 120, Gender = 'M' },
};
string whereExpression = "customer.Age > 18 && customer.Gender == 'F' && index >=0";
var interpreter = new Interpreter();
Func<Customer, int, bool> dynamicWhere = interpreter.ParseAsDelegate<Func<Customer, int, bool>>(whereExpression, "customer", "index");
Console.WriteLine(customers.Where(dynamicWhere).Count());
}
6.生成lambda表达式
我们可以使用Interpreter.ParseAsExpression<TDelegate>解释表达式直接生成lambda表达式;
static void DynamicLambdaExpress()
{
var customers = new List<Customer> {
new Customer() { Name = "David", Age = 31, Gender = 'M' },
new Customer() { Name = "Mary", Age = 29, Gender = 'F' },
new Customer() { Name = "Jack", Age = 2, Gender = 'M' },
new Customer() { Name = "Marta", Age = 1, Gender = 'F' },
new Customer() { Name = "Moses", Age = 120, Gender = 'M' },
}.AsQueryable();
string whereExpression = "customer.Age > 18 && customer.Gender == 'F' && index >=0";
var interpreter = new Interpreter();
Expression<Func<Customer, int, bool>> dynamicWhere = interpreter.ParseAsExpression<Func<Customer, int, bool>>(whereExpression, "customer", "index");
Console.WriteLine(customers.Where(dynamicWhere).Count());
}
7.支持的操作符
Category | Operators |
---|---|
Primary | x.y f(x) a[x] new typeof |
Unary | + - ! (T)x |
Multiplicative | * / % |
Additive | + - |
Relational and type testing | < > <= >= is as |
Equality | == != |
Logical AND | & |
Logical OR | |
Logical XOR | ^ |
Conditional AND | && |
Conditional OR | |
Conditional | ?: |
Assignment | = |
Null coalescing | ?? |
8.文本标识
Category | Operators |
---|---|
Constants | true false null |
Real literal suffixes | d f m |
Integer literal suffixes | u l ul lu |
String/char | "" '' |
字符串或者字符类型中支持的转译
- ' - single quote, needed for character literals
- " - double quote, needed for string literals
- - backslash