如何使用动态对象作为 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 数据的方法(它将双方都转换为对象):但是它适用于字符串。也许这是一个起点。