2012-05-01 2 views
3

Étant donné une expression arbitraire de type Expression<Func<int>>, comment puis-je obtenir une liste de tous les objets qui pourraient, mais pas nécessairement, affecter le résultat.Comment obtenir tous les facteurs d'un arbre d'expression qui affectent sa sortie

Je suis à la recherche d'une fonction comme ceci:

IEnumerable<object> GetFactors(Expression<Func<int>> expression) 
{ 
    //return a list of all objects in the expression that affect the result. 
} 

Exemple 1

Expression<Func<int>> expression =() => a + b; 

a et b sont int s, GetFactors reviendriez un IEnumerable<object> contenant a et b.

Exemple 2

Expression<Func<int>> expression =() => obj1 != obj2 ? a + b : c + d; 

GetFactors retournerait un IEnumerable<object> contenant obj1, obj2, a, b, c et d.

+0

Donc, fondamentalement, tous les points de terminaison (feuilles) ou voulez-vous également détecter le code mort? –

+0

@HenkHolterman: Je me fiche du code mort. Je cherche toutes les feuilles, code mort ou non. Je pense qu'il serait correct de dire que je m'intéresse à tous les opérandes de toutes les expressions de l'arbre. – Verax

Répondre

2

Vous devez implémenter une classe de visiteur d'expression personnalisée comme ceci:

public class FactorVisitor : ExpressionVisitor 
{ 
    List<object> factors = new List<object>(); 

    private FactorVisitor(Expression<Func<int>> expression) 
    { 
     Visit(expression); 
    } 

    public static List<object> GetFactors(Expression<Func<int>> expression) 
    { 
     return new FactorVisitor(expression).factors; 
    } 

    // Add this method for listing compile-time constant values 
    protected override Expression VisitConstant(ConstantExpression node) 
    { 
     factors.Add(node.Value); 
     return node; 
    } 

    protected override Expression VisitMember(MemberExpression node) 
    { 
     if (CanBeEvaluated(node)) 
     { 
      factors.Add(Evaluate(node)); 
     } 
     return node; 
    } 

    private static bool CanBeEvaluated(MemberExpression exp) 
    { 
     while (exp.Expression.NodeType == ExpressionType.MemberAccess) 
     { 
      exp = (MemberExpression) exp.Expression; 
     } 

     return (exp.Expression.NodeType == ExpressionType.Constant); 
    } 

    private static object Evaluate(Expression exp) 
    { 
     if (exp.NodeType == ExpressionType.Constant) 
     { 
      return ((ConstantExpression) exp).Value; 
     } 
     else 
     { 
      MemberExpression mexp = (MemberExpression) exp; 
      object value = Evaluate(mexp.Expression); 

      FieldInfo field = mexp.Member as FieldInfo; 
      if (field != null) 
      { 
       return field.GetValue(value); 
      } 
      else 
      { 
       PropertyInfo property = (PropertyInfo) mexp.Member; 
       return property.GetValue(value, null); 
      } 
     } 
    } 
} 

S'il vous plaît noter que vous obtenez seulement les valeurs des variables, même pour les appels membres comme a.b.

Questions connexes