从现有表达式在父对象上创建表达式树,以便进行c#mongodb驱动程序分析

本文关键字:表达式 驱动程序 c#mongodb 对象 创建 | 更新日期: 2023-09-27 18:29:05

我有一个这样的类:

public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
    // ...
}

我还有一个通用类,比如:

public class MyParentObject<T>
{
    public T Item { get; set; }
    // ...
}

例如,我有一个这样的表达式:

Expression<Func<Person, bool>> expression = p => p.Name == "MyName" && p.Email = "example@test.com"

如何将此表达式转换为:

Expression<Func<MyParentObject<Person>, bool>> expression = p => p.Item.Name == "MyName" && p.Item.Email = "example@test.com"

编辑:

我认为我的问题还不够深入,我想要这样的方法:

public static Expression<Func<MyParentObject<T>, bool>> GetParentExpression(Expression<Func<T, bool>> expression)
{
    Expression <Func<MyParentObject<T>, bool>> result = // process...
    // ...
    return result;
}

编辑:

我必须创建一个新的树表达式,然后由c#mongodb驱动程序进行解析。我不能在表达式树上使用Invoke和其他Compile方法。

我想我必须使用ExpressionVisitor,但我不知道如何。。。

从现有表达式在父对象上创建表达式树,以便进行c#mongodb驱动程序分析

您可以使用Expression.Invoke

public static Expression<Func<MyParentObject<T>, bool>> GetParentExpression<T>(Expression<Func<T, bool>> expression)
{
    Expression<Func<MyParentObject<T>, T>> item = parent => parent.Item;
    var result = Expression.Lambda<Func<MyParentObject<T>, bool>>(
        Expression.Invoke(expression, item.Body), item.Parameters);
    return result;
}

更新:另一种需要更多代码但消除Expression.Invoke的方法是使用ExpressionVisitor派生类来替换传递的表达式的参数,如

public static Expression<Func<MyParentObject<T>, bool>> GetParentExpression<T>(Expression<Func<T, bool>> expression)
{
    Expression<Func<MyParentObject<T>, T>> item = parent => parent.Item;
    var body = new ParameterExpressionReplacer { source = expression.Parameters[0], target = item.Body }.Visit(expression.Body);
    var result = Expression.Lambda<Func<MyParentObject<T>, bool>>(body, item.Parameters);
    return result;
}
class ParameterExpressionReplacer : ExpressionVisitor
{
    public ParameterExpression source;
    public Expression target;
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node == source ? target : base.VisitParameter(node);
    }
}