如何将一种类型的表达式树转换为不同的表达式类型?

如果我有两个几乎相同的类AnimalAnimalViewModel以及一个与viewmodel相关的表达式树,我该如何将它翻译成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; } } 

如何将Expression<Func>Expression<Func>

 public static Expression<Func> Translate (Expression<Func> expression) { // What goes here? I assume I have to traverse the tree somehow. } 

这是一个完成这项工作的访客。

  • 它创建了一个参数的副本(因为我们需要创建一个新参数并替换旧参数的所有引用)
  • .Body树的.Body ,替换参数,并将对类型的任何成员访问切换到类型的类似命名的成员
  • 它使用我们发明的参数重新组装一个lambda

码:

 class TypeChangeVisitor : ExpressionVisitor { private readonly Type from, to; private readonly Dictionary substitutions; public TypeChangeVisitor(Type from, Type to, Dictionary 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> predicate = x => x.Name == "abc"; var switched = Translate(predicate); } public static Expression> Translate(Expression> expression) { var param = Expression.Parameter(typeof(TTo), expression.Parameters[0].Name); var subst = new Dictionary { { expression.Parameters[0], param } }; var visitor = new TypeChangeVisitor(typeof(TFrom), typeof(TTo), subst); return Expression.Lambda>(visitor.Visit(expression.Body), param); } } 

请注意,如果你有x.Something.Name你可能需要更加小心,但这应该让你有一个合理的方法。

您是否尝试过Automapper这样的事情?