我怎样一种类型的前pression树转换成不同的前pression类型? [英] How do I translate an expression tree of one type to a different expression type?
本文介绍了我怎样一种类型的前pression树转换成不同的前pression类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
如果我有两个几乎相同的类动物
和 AnimalViewModel
和相关的前pression树视图模型,我怎么能转化为动物
?
公共类动物
{
公共字符串物种{搞定;组; }
公共字符串名称{;组; }
公共字符串声音{搞定;组; }
}
公共类AnimalViewModel:ViewModelBase
{
公共字符串物种{搞定;组; }
公共字符串名称{;组; }
公共字符串声音{搞定;组; }
}
我怎么能翻译的防爆pression< Func键< AnimalViewModel,布尔>>
到防爆pression< Func键<动物,布尔>>
公共静态防爆pression<&Func键LT;动物,布尔>>翻译(前pression<&Func键LT; AnimalViewModel,布尔>>前pression)
{
//善有善报吗?我想我必须以某种方式遍历树。
}
解决方案
下面是做这项工作的访问者。
- 它使得参数的副本(因为我们需要为新创建一个新的参数,并替换旧的参数的所有引用)
- 它走了
。体
树的,替代的参数,切换到喜欢 - 对老的类型的任何成员访问上的新的的类型 命名成员 - 使用它,我们早期的版本发明了参数重新组装的lambda
code:
类TypeChangeVisitor:防爆pressionVisitor
{
从,私人只读类型;
私人只读字典<防爆pression,防爆pression>换人;
公共TypeChangeVisitor(从类型,类型为,字典<防爆pression,防爆pression>替代)
{
this.from =距离;
this.to =到;
this.substitutions =换人;
}
公共覆盖防爆pression访问(防爆pression节点)
{//一般取代(例如,参数交换)
防爆pression找到;
如果(替代= NULL&放大器;!&安培; substitutions.TryGetValue(节点,出于找到))
{
返回找到;
}
返回base.Visit(节点);
}
保护覆盖防爆pression VisitMember(MemberEx pression节点)
{//如果我们看到x.Name在旧型,替代型新
如果(node.Member.DeclaringType ==从)
{
返回前pression.MakeMemberAccess(访问(node.Ex pression)
to.GetMember(node.Member.Name,node.Member.MemberType,
BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic可)。单());
}
返回base.VisitMember(节点);
}
}
公共类节目
{
公共静态无效的主要()
{
防爆pression<&Func键LT; AnimalViewModel,布尔>> predicate = X => x.Name ==ABC;
VAR切换=翻译< AnimalViewModel,动物>(predicate);
}
公共静态防爆pression<&Func键LT,TTO,布尔>>翻译< TFrom,TTO>(防爆pression<&Func键LT; TFrom,布尔>>前pression)
{
VAR参数=前pression.Parameter(typeof运算(TTO),前pression.Parameters [0] .Name点);
VAR SUBST =新词典<防爆pression,防爆pression> {{前pression.Parameters [0],参数}};
VAR访客=新TypeChangeVisitor(typeof运算(TFrom)的typeof(TTO),SUBST);
返回前pression.Lambda<&Func键LT,TTO,布尔>>(visitor.Visit(如pression.Body),参数);
}
}
请注意,如果您有 x.Something.Name
您可能需要有点更加小心,但是这应该给你一个合理的方式。
If I have two nearly identical classes Animal
and AnimalViewModel
and an expression tree related to the viewmodel, how can I translate it to Animal
?
public class Animal
{
public string Species { get; set; }
public string Name { get; set; }
public string Sound { get; set; }
}
public class AnimalViewModel : ViewModelBase
{
public string Species { get; set; }
public string Name { get; set; }
public string Sound { get; set; }
}
How can I translate an Expression<Func<AnimalViewModel,bool>>
to Expression<Func<Animal,bool>>
?
public static Expression<Func<Animal,bool>> Translate (Expression<Func<AnimalViewModel,bool>> expression)
{
// What goes here? I assume I have to traverse the tree somehow.
}
解决方案
Here's a visitor that does the job.
- it makes a copy of the parameter (since we'll need to create a new parameter and substitute all references of the old parameter for the new one)
- it walks the
.Body
of the tree, substituting the parameter, and switching any member-access against the old type to a like-named member on the new type - it re-assembles a lambda using the parameter we invented earler
Code:
class TypeChangeVisitor : ExpressionVisitor
{
private readonly Type from, to;
private readonly Dictionary<Expression, Expression> substitutions;
public TypeChangeVisitor(Type from, Type to, Dictionary<Expression, Expression> substitutions)
{
this.from = from;
this.to = to;
this.substitutions = substitutions;
}
public override Expression Visit(Expression node)
{ // general substitutions (for example, parameter swaps)
Expression found;
if(substitutions != null && substitutions.TryGetValue(node, out found))
{
return found;
}
return base.Visit(node);
}
protected override Expression VisitMember(MemberExpression node)
{ // if we see x.Name on the old type, substitute for new type
if (node.Member.DeclaringType == from)
{
return Expression.MakeMemberAccess(Visit(node.Expression),
to.GetMember(node.Member.Name, node.Member.MemberType,
BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Single());
}
return base.VisitMember(node);
}
}
public class Program
{
public static void Main()
{
Expression<Func<AnimalViewModel, bool>> predicate = x => x.Name == "abc";
var switched = Translate<AnimalViewModel, Animal>(predicate);
}
public static Expression<Func<TTo, bool>> Translate<TFrom, TTo>(Expression<Func<TFrom, bool>> expression)
{
var param = Expression.Parameter(typeof(TTo), expression.Parameters[0].Name);
var subst = new Dictionary<Expression, Expression> { { expression.Parameters[0], param } };
var visitor = new TypeChangeVisitor(typeof(TFrom), typeof(TTo), subst);
return Expression.Lambda<Func<TTo, bool>>(visitor.Visit(expression.Body), param);
}
}
Note that if you have x.Something.Name
you might need to be a bit more careful, but this should get you a reasonable way.
这篇关于我怎样一种类型的前pression树转换成不同的前pression类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文