Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding out if an Expression contains a "lonely" ParameterExpression

Tags:

c#

expression

Is there a simple way of finding out if an Expression contains a ParameterExpression that isn't further wrapped in for example a MemberExpression.

Example:

x => x.Method() ? x : null <= 1 occurence of x without any further evaluation

x => x.Method() ? x.Property : null <= 0 occurences of x without any further evaluation

Simply put my use case is that I know the Method (no params) and Property values and want to find out if this is enough to evaluate the expression without fetching the entire "object" from store.

Edit: My example is maybe to simplified. There are more Expression types that needs to be handled (for example UnaryExpression).

x => ((Cast) x).Property <= 0 occurences of x without any further evaluation

I'm looking for an answer to the following question:

given an expression, if I know all method return values and property values of the input parameter but not the parameter value itself, can I evaluate the expression?

like image 804
lindstromhenrik Avatar asked Oct 05 '12 13:10

lindstromhenrik


1 Answers

If you are on .NET 4 or later, you can use ExpressionVisitor for this.

I'm not quite sure how you define "lonely parameter", but if you want to exclude direct method calls, member accesses and indexer accesses on parameters, you can use something like this (untested):

Use it like this:

new MyExpressionVisitor().GetNumLonelyParameterExpressions(myExpression.Body)

public class MyExpressionVisitor : ExpressionVisitor
{
    private int numLonelyParameterExpressions;

    public int GetNumLonelyParameterExpressions(Expression expression)
    {
        numLonelyParameterExpressions = 0;
        Visit(expression);
        return numLonelyParameterExpressions;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        // Every time we encounter a lonely parameter, increment.
        numLonelyParameterExpressions++;
        return base.VisitParameter(node);
    }

    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        // Don't visit parameters that have methods called on them.
         var expr = (node.Object is ParameterExpression)
            ? Expression.Default(node.Object.Type)
            : node.Object;

        // We need to make sure the arguments are visited though.
        return base.VisitMethodCall(node.Update(expr, node.Arguments));
    }


    protected override Expression VisitMember(MemberExpression node)
    {
          // Don't visit parameters with member accesses on them.
          if (node.Expression is ParameterExpression)
              return Expression.Default(node.Type);

          return base.VisitMember(node);
    }

    protected override Expression VisitIndex(IndexExpression node)
    {
         // Same idea here.
         var expr = (node.Object is ParameterExpression)
             ? Expression.Default(node.Object.Type)
             : node.Object;

         return base.VisitIndex(node.Update(expr, node.Arguments));
    }
}
like image 58
Ani Avatar answered Oct 27 '22 01:10

Ani