views:

67

answers:

3

Hello there,

I have just found some misterious behaviour while working with System.Linq.Expressions.Expression and System.Reflection.MethodInfo.

The code is as follows:

    static void Main(string[] args)
    {

        Expression<Func<double, double, double>> example = (x, y) => Math.Sin(x);

        //Prints out "x, y":
        Console.WriteLine(example.Parameters[0].Name + ", " + example.Parameters[1].Name);

        //Prints out "a":
        Console.WriteLine((example.Body as MethodCallExpression).Method.GetParameters()[0].Name);

    }

"a"? Where did my "x" go and where did this "a" come from?

Thinking that perhaps this is an alias used at low level, I have searched for "UsedName", "VisibleName" or something along those lines, but I haven't found anything.

Unfortunately, Expression does not feature a Parameters property (I believe only LambdaExpression does) which would return the "parameters in use", if any, in a given expression.

One can create a method that traverses the entire expression and collects the different parameters in use, but I was wondering if there is an easier way to do this.

Thanks a lot in advance.

Visual C# Express: 10.0.30319.1 RTMRel

.NET Framework: 4.0.30319 RTMRel

+2  A: 

The a comes from the method you're calling - Math.Sin. x and y are parameters to your lambda expression; a is the parameter in Math.Sin.

If you want to get back x and y, cast example to LambdaExpression:

foreach (ParameterExpression p in example.Parameters)
{
    Console.WriteLine(p.Name); // Prints x then y
}

So no, there's no inconsistency here.

EDIT: If you want to find the arguments used in the method call - and you're sure it is just a method call, and the arguments will just be parameters - you can use something like:

var methodCall = (MethodCallExpression) example.Body;

// Implicitly casts each argument to ParameterExpression
foreach (ParameterExpression p in methodCall.Arguments)
{
    Console.WriteLine(p.Name);
}

In this case, it just prints out x as that's what's being used as the argument to Math.Sin.

Jon Skeet
Now I understand that I wasn't really comparing apples to apples, so agreed that there is no inconsistency. On the other hand: why the cast? I can already access `Parameters`, `Body`, etc. directly from `example`, which (I believe) is of type `LambdaExpression`. What I think would be really useful is something like this: `ParameterExpression[] parameters = (anyExpressionInstance as LambdaExpression).Parameters.ToArray();`. In this specific case, `(example.Body as LambdaExpression)` would become `x => Math.Sin(x)`, from where I could retrieve the "parameter in use" `x`.
Blas de Lezo
@Blas: True - I cast because of your paragraph starting "Unfortunately" - but yes, I'd forgotten that you've actually got an `Expression<T>`, not just an Expression`. So yes, you don't need the cast. I'll edit my answer. Personally I would cast rather than using `as` though, in your comment code - a NullReferenceException isn't as useful as an `InvalidCastException`.
Jon Skeet
@Blas: Just rereading your comment, it sounds like you want the *arguments* to the method call. Editing...
Jon Skeet
A: 

Place the cursor over Sin in Visual Studio. Press the F12 key. Here's where a comes from. It comes from a developer in Redmond who decided to name it like this :-)

Darin Dimitrov
I see, so "a" is just the "hardcoded" parameter name of the function Sin.
Blas de Lezo
Yes, this is where it comes from.
Darin Dimitrov
A: 

Thanks guys, that solves it (sorry, but I can't add comments or do anything after I closed my browser).

Blas de Lezo