如何更改表达式目录树类型? [英] How to change a type in an expression tree?

查看:135
本文介绍了如何更改表达式目录树类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样一个方法:

 私人布尔Method_1(表达式来; Func键< IPerson,布尔>>表达式) 
{
/ *一些代码,将调用Method_2 * /
}

在这个方法我想改变 IPerson 键入另一种类型。我想打电话,看起来像这样的另一种方法:

 私人布尔Method_2(表达式来; Func键< PersonData,布尔>>表达)
{
/ *一些代码* /
}

所以,在 method_1 我需要改变 IPerson PersonData 。我怎样才能做到这一点。



编辑:



当我打电话: Method_1( p => p.Id == 1)我要拯救的条件( p.Id == 1 ),但我想在另一种类型执行这个条件,即 IPerson 。所以,我需要改变的表达或创建 IPerson



编辑II新的表达式:



对于那些谁感兴趣的话,这就是(现在)我的解决方案:

 私有类CustomExpressionVisitor< T> :ExpressionVisitor 
{
ParameterExpression _parameter;

公共CustomExpressionVisitor(ParameterExpression参数)
{
_parameter =参数;
}

保护覆盖表达VisitParameter(ParameterExpression节点)
{
返回_parameter;
}

保护覆盖表达VisitMember(MemberExpression节点)
{
如果(node.Member.MemberType == System.Reflection.MemberTypes.Property)
{
MemberExpression memberExpression = NULL;
VAR memberName = node.Member.Name;
VAR otherMember = typeof运算(T).GetProperty(memberName);
memberExpression = Expression.Property(访问(node.Expression),otherMember);
返回memberExpression;
}
,否则
{
返回base.VisitMember(节点);
}
}
}



这是我的方式使用它:

 公共虚拟BOOL存在(表达式来; Func键< D​​TO,布尔>>表达式)
{
VAR参数= Expression.Parameter(typeof运算(I));
VAR的结果=新CustomExpressionVisitor< I>(参数).Visit(expression.Body);
表达式来; Func键<我,布尔>>波长= Expression.Lambda<&Func键LT;我,布尔>>(结果,参数);

布尔存在= _repository.Exists(拉姆达);
回报率的存在;
}


解决方案

如果你使用很容易.NET 4中(更新:在注释中提到的第4版4.5不加入 ExpressionVisitor ),这将需要一些谷歌上搜索老年人框架:



有一些假设,但我认为它们是有效为您的DTO和实体场景 - 访问必须匹配的属性。

 类PersonData 
{
公共BOOL道具{搞定;组; }
}

接口IPerson
{
布尔道具{搞定;组; }
}

在.NET 4中有 ExpressionVisitor 类定义使这是一个容易得多,如果你使用旧之一,那么你需要写或发现实施它:

 类参观者< T> :ExpressionVisitor 
{
ParameterExpression _parameter;

//必须有每个参数
参数表达的只有一个实例//有一个,这样一个在这里通过
公众参观(ParameterExpression参数)
{
_parameter =参数;
}

//此方法取代,在构造函数中
保护覆盖表达VisitParameter(ParameterExpression节点)
{
返回_parameter给原来的参数;
}

//因为PersonData没有实现IPerson这个是必需的,它发现
//属性PersonData具有相同的名称作为一个在表达$ B $引用b //并宣布IPerson
保护覆盖表达VisitMember(MemberExpression节点)
{
//如果你使用的字段,那么你需要扩展
属性只有允许//这方法来处理它们
如果(node.Member.MemberType = System.Reflection.MemberTypes.Property!)
抛出新NotImplementedException();

//矿山道具
VAR memberName = node.Member.Name原始表达式中引用你的
//样品标识成员的名称;
的名字
VAR otherMember = typeof运算(T).GetProperty(memberName)//找到T型(= PersonData)财产;
//访问给这个表达式p.Id的一面,这将是p
变种内=访问(node.Expression);
返回Expression.Property(内,otherMember);
}
}理念



证明:

 类节目
{
静态无效的主要()
{
//样品表达
表达式来; Func键< IPerson,布尔>>表达式= X => x.Prop;

//参数将在产生表达
VAR参数用于= Expression.Parameter(typeof运算(PersonData));
//访问原始表达式的身体,让我们的新的表达
变种体=新访客与LT的身体; PersonData>(参数).Visit(expression.Body);
//生成lambda表达式形式的身体和参数
//注意,这是你需要调用Method_2
表达式来什么,Func键< PersonData,布尔>>波长= Expression.Lambda<&Func键LT; PersonData,布尔>>(机身,参数);
//编译和产生方法的执行只是为了证明它的作品
VAR boolValue = lambda.Compile()(新PersonData());
}
}

请注意,这将简单表达式的工作。如果您需要处理 x.Prop.Prop1< 3 则需要进一步扩大这一点。


I have a method like this:

private bool Method_1(Expression<Func<IPerson, bool>> expression)
{
    /* Some code that will call Method_2 */
}

In this method I want to change the IPerson type to another type. I want to call another method that looks like this:

private bool Method_2(Expression<Func<PersonData, bool>> expression)
{
    /* Some code */
}

So, in method_1 I need to change IPerson to PersonData. How can I do this?

Edit:

When I call: Method_1(p => p.Id == 1) I want to 'save' the condition (p.Id == 1) but I want to execute this condition on another type, namely IPerson. So, I need to alter the expression or create a new expression with IPerson

EDIT II:

For those who are interested, this is (for now) my solution:

private class CustomExpressionVisitor<T> : ExpressionVisitor
{
    ParameterExpression _parameter;

    public CustomExpressionVisitor(ParameterExpression parameter)
    {
        _parameter = parameter;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return _parameter;
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.Member.MemberType == System.Reflection.MemberTypes.Property)
        {
            MemberExpression memberExpression = null;
            var memberName = node.Member.Name;
            var otherMember = typeof(T).GetProperty(memberName);
            memberExpression = Expression.Property(Visit(node.Expression), otherMember);
            return memberExpression;
        }
        else 
        {
            return base.VisitMember(node);
        }
    }
}

And this is the way I use it:

public virtual bool Exists(Expression<Func<Dto, bool>> expression)
{
    var param = Expression.Parameter(typeof(I));
    var result = new CustomExpressionVisitor<I>(param).Visit(expression.Body);
    Expression<Func<I, bool>> lambda = Expression.Lambda<Func<I, bool>>(result, param);

    bool exists = _repository.Exists(lambda);
    return exists;
}

解决方案

It is easy if you use .net 4 (update: as noted in comment ExpressionVisitor was added in version 4 not 4.5) it would require some googling for older frameworks:

There are some assumptions but I think they are valid for your DTO and Entity scenario - properties accessed must match.

class PersonData
{
    public bool Prop { get; set; }
}

interface IPerson 
{
    bool Prop { get; set; }
}

In .net 4 there is ExpressionVisitor class defined that makes this a lot easier if you use older one then you need to write or find implementation of it:

class Visitor<T> : ExpressionVisitor
{
    ParameterExpression _parameter;

    //there must be only one instance of parameter expression for each parameter 
    //there is one so one passed here
    public Visitor(ParameterExpression parameter)
    {
        _parameter = parameter;
    }

    //this method replaces original parameter with given in constructor
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return _parameter;
    }

    //this one is required because PersonData does not implement IPerson and it finds
    //property in PersonData with the same name as the one referenced in expression 
    //and declared on IPerson
    protected override Expression VisitMember(MemberExpression node)
    {
        //only properties are allowed if you use fields then you need to extend
        // this method to handle them
        if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
            throw new NotImplementedException();

        //name of a member referenced in original expression in your 
        //sample Id in mine Prop
        var memberName = node.Member.Name;
        //find property on type T (=PersonData) by name
        var otherMember = typeof(T).GetProperty(memberName);
        //visit left side of this expression p.Id this would be p
        var inner = Visit(node.Expression);
        return Expression.Property(inner, otherMember);
    }
}

Proof of concept:

class Program
{
   static void Main()
    {
        //sample expression
        Expression<Func<IPerson, bool>> expression = x => x.Prop;

        //parameter that will be used in generated expression
        var param = Expression.Parameter(typeof(PersonData));
        //visiting body of original expression that gives us body of the new expression
        var body = new Visitor<PersonData>(param).Visit(expression.Body);
        //generating lambda expression form body and parameter 
        //notice that this is what you need to invoke the Method_2
        Expression<Func<PersonData, bool>> lambda = Expression.Lambda<Func<PersonData, bool>>(body, param);
        //compilation and execution of generated method just to prove that it works
        var boolValue = lambda.Compile()(new PersonData());
    }
}

Note that this will work for simple expressions. If you need to handle x.Prop.Prop1 < 3 then you need to extend this further.

这篇关于如何更改表达式目录树类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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