如何使用动态对象作为 lambda 表达式的输入?
How to work with dynamic objects as input for lambda expressions?
我想将表达式存储在数据库中以维护规则引擎。表达式采用此示例的形式:
Expression<Func<MyTerm, bool>> expression = t => t.MyProperty == SomeValue;
我面临的问题是我必须在运行时创建 MyTerm。为了仍然能够将 MyTerm 用作 lambda 表达式的参数,我使用 ExpandoObject 实现了一个解决方案,如下所示:
public class MyTerm
{
ExpandoObject ParameterSet;
public void AddParameter(string name, object value)
{
IDictionary<string, object> dictionary = ParameterSet as IDictionary<string, object>;
if (dictionary.ContainsKey(name))
{
dictionary[name] = value;
}
else
{
dictionary.Add(name, value);
}
}
public string GetString(string name)
{
IDictionary<string, object> dictionary = ParameterSet as IDictionary<string, object>;
if (dictionary.ContainsKey(name))
{
return (string)dictionary[name];
}
throw new KeyNotFoundException("Term does not contain parameter {name}.");
}
问题是,我获得了能够在运行时向 MyTerm 添加参数的优势,但我必须为每个 getter 指定 return 类型,而不是能够使用上面的语法:
t.MyProperty
有没有办法使用动态对象作为 lambda 表达式的输入,或者有没有办法像这样为 类 编写扩展方法以便 return 对象而不是特定类型?我能够像这样编译表达式:
public static Func<MyTerm, bool> Compile(string body)
{
ParameterExpression term = Expression.Parameter(typeof(MyTerm), typeof(MyTerm).Name);
LambdaExpression exp = DynamicExpressionParser.ParseLambda(new[] { term }, typeof(bool), body);
return (Func<DynamicTerm, bool>)exp.Compile();
}
static void Main(string[] args)
{
MyTerm term = new MyTerm();
term.AddParameter("SomeParameter", "SomeValue");
Func<MyTerm, bool> IsGreaterThanSomeParameter = Compile("MyTerm.GetString(\"SomeParameter\")== SomeValue);
bool result = IsGreaterThanSomeParameter(term);
Console.WriteLine(result);
Console.ReadLine();
}
我想存储独立于特定实现的 lambda 表达式,因此如果另一个服务试图将这些表达式编译回函数,语法应该是开箱即用的。没有任何解决方法 getters。
提前谢谢你。
事实证明,如果您的对象上有索引器,System.Linq.Dynamic 会在找不到匹配的 属性 时尝试调用它。
public class DynamicTerm
{
private readonly Dictionary<string, object> store = new Dictionary<string, object>();
public void Set(string key, object value) => store[key] = value;
public object this[string key] => store[key];
}
public static void Main()
{
string body = "Term.SomeProperty == \"foo\"";
ParameterExpression termExpr = Expression.Parameter(typeof(DynamicTerm), "Term");
var exp = DynamicExpressionParser.ParseLambda(new[] { termExpr }, typeof(bool), body);
var compiled = (Func<DynamicTerm, bool>)exp.Compile();
var term = new DynamicTerm();
term.Set("SomeProperty", "foo");
Console.WriteLine(compiled(term));
}
我找不到返回 typed 数据的方法(它将双方都转换为对象):但是它适用于字符串。也许这是一个起点。
我想将表达式存储在数据库中以维护规则引擎。表达式采用此示例的形式:
Expression<Func<MyTerm, bool>> expression = t => t.MyProperty == SomeValue;
我面临的问题是我必须在运行时创建 MyTerm。为了仍然能够将 MyTerm 用作 lambda 表达式的参数,我使用 ExpandoObject 实现了一个解决方案,如下所示:
public class MyTerm
{
ExpandoObject ParameterSet;
public void AddParameter(string name, object value)
{
IDictionary<string, object> dictionary = ParameterSet as IDictionary<string, object>;
if (dictionary.ContainsKey(name))
{
dictionary[name] = value;
}
else
{
dictionary.Add(name, value);
}
}
public string GetString(string name)
{
IDictionary<string, object> dictionary = ParameterSet as IDictionary<string, object>;
if (dictionary.ContainsKey(name))
{
return (string)dictionary[name];
}
throw new KeyNotFoundException("Term does not contain parameter {name}.");
}
问题是,我获得了能够在运行时向 MyTerm 添加参数的优势,但我必须为每个 getter 指定 return 类型,而不是能够使用上面的语法:
t.MyProperty
有没有办法使用动态对象作为 lambda 表达式的输入,或者有没有办法像这样为 类 编写扩展方法以便 return 对象而不是特定类型?我能够像这样编译表达式:
public static Func<MyTerm, bool> Compile(string body)
{
ParameterExpression term = Expression.Parameter(typeof(MyTerm), typeof(MyTerm).Name);
LambdaExpression exp = DynamicExpressionParser.ParseLambda(new[] { term }, typeof(bool), body);
return (Func<DynamicTerm, bool>)exp.Compile();
}
static void Main(string[] args)
{
MyTerm term = new MyTerm();
term.AddParameter("SomeParameter", "SomeValue");
Func<MyTerm, bool> IsGreaterThanSomeParameter = Compile("MyTerm.GetString(\"SomeParameter\")== SomeValue);
bool result = IsGreaterThanSomeParameter(term);
Console.WriteLine(result);
Console.ReadLine();
}
我想存储独立于特定实现的 lambda 表达式,因此如果另一个服务试图将这些表达式编译回函数,语法应该是开箱即用的。没有任何解决方法 getters。 提前谢谢你。
事实证明,如果您的对象上有索引器,System.Linq.Dynamic 会在找不到匹配的 属性 时尝试调用它。
public class DynamicTerm
{
private readonly Dictionary<string, object> store = new Dictionary<string, object>();
public void Set(string key, object value) => store[key] = value;
public object this[string key] => store[key];
}
public static void Main()
{
string body = "Term.SomeProperty == \"foo\"";
ParameterExpression termExpr = Expression.Parameter(typeof(DynamicTerm), "Term");
var exp = DynamicExpressionParser.ParseLambda(new[] { termExpr }, typeof(bool), body);
var compiled = (Func<DynamicTerm, bool>)exp.Compile();
var term = new DynamicTerm();
term.Set("SomeProperty", "foo");
Console.WriteLine(compiled(term));
}
我找不到返回 typed 数据的方法(它将双方都转换为对象):但是它适用于字符串。也许这是一个起点。