preorden ordenar metodo binario arbol c# c#-4.0 lambda expression-trees

c# - ordenar - ¿Cómo puedo traducir un árbol de expresiones de un tipo a un tipo de expresión diferente?



metodo preorden c# (2)

Si tengo dos clases casi idénticas Animal y AnimalViewModel y un árbol de expresión relacionado con el modelo de vista, ¿cómo puedo traducirlo a 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; } }

¿Cómo puedo traducir una Expression<Func<AnimalViewModel,bool>> a 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. }


Aquí hay un visitante que hace el trabajo.

  • hace una copia del parámetro (ya que necesitaremos crear un nuevo parámetro y sustituir todas las referencias del parámetro anterior por el nuevo)
  • .Body el .Body del árbol, sustituye el parámetro y cambia cualquier acceso de miembro por el tipo anterior a un miembro de nombre similar en el nuevo tipo
  • reensambla un lambda usando el parámetro que hemos inventado Earler

Código:

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); } }

Tenga en cuenta que si tiene x.Something.Name es posible que deba ser un poco más cuidadoso, pero esto debería hacerlo de una manera razonable.