4

For the following Lambda expression:

GetPropertyNameAndArrayIndex(() => SomeArray[0])

I know that you can get the property name for an expression. I also know that you can get the array index by using a ConstantExpression and accessing the Right value. My question is how do you get array index (or Right value) when it is not a constant, I.E.,

for (int i = 0; i < 5; i++)
{
    GetPropertyNameAndArrayIndex(() => SomeArray[i])
}

Any help would be greatly appreciated.

Community
  • 1
  • 1
Kane
  • 16,471
  • 11
  • 61
  • 86
  • Please edit. A verb is missing in "I know that you can [missing verb] the property name and the array index " – Emilio M Bumachar Oct 05 '09 at 20:56
  • @Emilio thanks for pointing out my poor grammar :) – Kane Oct 05 '09 at 21:05
  • 3
    Be careful with that snippet: the lambda will capture the i _variable_ in a closre, not the value of the variable at the time it's created. You go call the function later and the expression created in all the iterations will evaluate as if they were created in the last iteration. – Joel Coehoorn Oct 05 '09 at 21:07
  • To clarify: I think you're probably okay here, because it looks like each iteration will call and use the lambda delegate before moving on to the next, rather than save it somewhere. But it's worth remembering. – Joel Coehoorn Oct 05 '09 at 21:09

1 Answers1

3

As already noted in comments; note that the example given is susceptible to issues with captured variables if used asynchronously - but probably OK "as is".

To do it thoroughly involves a lot of edge-cases (or you can cheat and use Compile()) - but here's an example that shows the overall themes (without using Compile):

using System;
using System.Linq.Expressions;
using System.Reflection;
class Program
{
    static void Main()
    {
        string[] arr = { "abc", "def" };
        for (int i = 0; i < arr.Length; i++)
        {
            Foo(() => arr[i]);
        }
    }
    static object Foo<T>(Expression<Func<T>> lambda)
    {
        object obj = Walk(lambda.Body);
        Console.WriteLine("Value is: " + obj);
        return obj;

    }
    static object Walk(Expression expr)
    {
        switch (expr.NodeType)
        {
            case ExpressionType.ArrayIndex:

                BinaryExpression be = (BinaryExpression)expr;
                Array arr = (Array)Walk(be.Left);
                int index = (int) Walk(be.Right);
                Console.WriteLine("Index is: " + index);
                return arr.GetValue(index);
            case ExpressionType.MemberAccess:
                MemberExpression me = (MemberExpression)expr;
                switch (me.Member.MemberType)
                {
                    case MemberTypes.Property:
                        return ((PropertyInfo)me.Member).GetValue(Walk(me.Expression), null);
                    case MemberTypes.Field:
                        return ((FieldInfo)me.Member).GetValue(Walk(me.Expression));
                    default:
                        throw new NotSupportedException();
                }
            case ExpressionType.Constant:
                return ((ConstantExpression) expr).Value;
            default:
                throw new NotSupportedException();

        }
    }

}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900