Finding out if an Expression contains a "lonely" ParameterExpression
Asked Answered
M

1

7

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?

Maxinemaxiskirt answered 5/10, 2012 at 13:38 Comment(2)
What version of .NET are you using?Exhilarative
It's .net 3.5 (but I also have a .net 4 version where I could use this)Maxinemaxiskirt
P
1

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));
    }
}
Politic answered 5/10, 2012 at 14:3 Comment(3)
This is my current approach (I have my own ExpressionVisitor for 3.5). However there are more Expressions that needs to be counted and I'm afraid I missing some. One is for example UnaryExpression: x => ((Cast) x).Property.Maxinemaxiskirt
@lindstromhenrik: I guess you're going to have to define 'lonely' really well as if you include that, it's pretty vague.Politic
I've tried to give a better explaination but I'm still not really sure what to call the problem ;-)Maxinemaxiskirt

© 2022 - 2024 — McMap. All rights reserved.