转换Linq表达式" obj => obj.Prop"变成" parent => parent.obj.Prop" [英] Convert Linq expression "obj => obj.Prop" into "parent => parent.obj.Prop"

查看:62
本文介绍了转换Linq表达式" obj => obj.Prop"变成" parent => parent.obj.Prop"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类型为Expression<Func<T, object>>的现有表达式;它包含cust => cust.Name之类的值.

I have an existing expression of type Expression<Func<T, object>>; it contains values like cust => cust.Name.

我还有一个父类,其字段类型为T.我需要一个接受上述内容作为参数并生成一个将父类(TModel)作为参数的新表达式的方法.它将用作MVC方法的表达参数.

I also have a parent class with a field of type T. I need a method that accepts the above as a parameter and generates a new expression that takes the parent class (TModel) as a parameter. This will be used as an expression parameter of an MVC method.

因此,cust => cust.Name变为parent => parent.Customer.Name.

同样,cust => cust.Address.State变为parent => parent.Customer.Address.State.

这是我的初始版本:

    //note: the FieldDefinition object contains the first expression
    //described above, plus the MemberInfo object for the property/field
    //in question
    public Expression<Func<TModel, object>> ExpressionFromField<TModel>(FieldDefinition<T> field)
        where TModel: BaseModel<T>
    {
        var param = Expression.Parameter(typeof(TModel), "t");

        //Note in the next line "nameof(SelectedItem)". This is a reference
        //to the property in TModel that contains the instance from which
        //to retrieve the value. It is unqualified because this method
        //resides within TModel.
        var body = Expression.PropertyOrField(param, nameof(SelectedItem));
        var member = Expression.MakeMemberAccess(body, field.Member);
        return Expression.Lambda<Func<TModel, object>>(member, param);
    }

我当前收到的错误是当我有一个包含多个部分的字段(即cust.Address.State而不只是cust.Name)时.我在var member行上收到一个错误,指出指定的成员不存在-这是正确的,因为该处的主体是指父母的孩子(Customer),而不是包含该成员的项目().

The error I'm currently receiving is when I have a field with multiple parts (i.e. cust.Address.State instead of just cust.Name). I get an error on the var member line that the specified member doesn't exist--which is true, since the body at that refers to the parent's child (Customer) and not the item that contains the member (Address).

这就是我希望我能做的:

Here's what I wish I could do:

    public Expression<Func<TModel, object>> ExpressionFromField<TModel>(FieldDefinition<T> field)
        where TModel: BaseModel<T>
    {
        var param = Expression.Parameter(typeof(TModel), "t");
        var body = Expression.PropertyOrField(param, nameof(SelectedItem));
        var IWantThis = Expression.ApplyExpressionToField(field.Expression, body);
        return Expression.Lambda<Func<TModel, object>>(IWantThis, param);
    }

到此为止的任何帮助将不胜感激.

Any help getting to this point would be greatly appreciated.

这被标记为

This was marked as a possible duplicate of this question; however, the only real similarity is the solution (which is, in fact, the same). Composing expressions is not an intuitive solution to accessing nested properties via expressions (unless one's inuition is guided by certain experience, which should not be assumed). I also edited the question to note that the solution needs to be suitable for a paramter of an MVC method, which limits the possible solutions.

推荐答案

您正在寻找的是能够表达表达式的功能,就像您可以编写函数一样:

What you're looking for is the ability to compose expressions, just as you can compose functions:

public static Expression<Func<T, TResult>> Compose<T, TIntermediate, TResult>(
    this Expression<Func<T, TIntermediate>> first,
    Expression<Func<TIntermediate, TResult>> second)
{
    return Expression.Lambda<Func<T, TResult>>(
        second.Body.Replace(second.Parameters[0], first.Body),
        first.Parameters[0]);
}

这依靠以下方法将一个表达式的所有实例替换为另一个:

This relies on the following method to replace all instances of one expression with another:

public class ReplaceVisitor:ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }

    public override Expression Visit(Expression ex)
    {
        if(ex == from) return to;
        else return base.Visit(ex);
    }  
}

public static Expression Replace(this Expression ex,
    Expression from,
    Expression to)
{
    return new ReplaceVisitor(from, to).Visit(ex);
}

您现在可以使用表达式选择属性:

You can now take an expression selecting a property:

Expression<Func<Customer, object>> propertySelector = cust => cust.Name;

还有一个从模型中选择该对象的表达式:

And an expression selecting that object from the model:

Expression<Func<CustomerModel, Customer>> modelSelector = model => model.Customer;

并撰写它们:

Expression<Func<Customer, object> magic = modelSelector.Compose(propertySelector);

这篇关于转换Linq表达式&quot; obj =&gt; obj.Prop"变成&quot; parent =&gt; parent.obj.Prop"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆