Search code examples
c#arraysexpression-trees

Expression-Tree for array property


Suppose we have this class

class ClassA
{
    public ClassB[] MyProperty { get; set; }
}
class ClassB
{
    public int[] AnotherProperty { get; set; }
}

Now I want to access the value for AnotherProperty for a given instance of ClassA and an array of indexes that reflect the two arrays So { 3 , 5 } e.g. means the fourth element within the top-level (evaluates to MyProperty) and the sixth element within second level (AnotherProperty). Thus I´m going to create a Func<ClassA, int[], int> by the means of an expression-tree:

var instanceArgument = Expression.Parameter(typeof(MyClass), "x");
var indexesArgument = Expression.Parameter(typeof(int[]), "i");

var expr = instanceArgument;
expr = Expression.Property(expr, "MyProperty");
expr = Expression.ArrayIndex(expr, ???);
expr = Expression.Property(expr, "AnotherProperty");
expr = Expression.ArrayIndex(expr, ???);
var f = Expression.Lambda<Func<ClassA, int[], int>>(expr, instanceArgument, indexesArgument);

As you can see I´m unsure on how to provide the indexes to the expression. I know I have to use the indexesArgument which reflects the indexes passed to our delegate, but how to access the values 3 and 5?


Solution

  • We need a further ArrayIndexExpression to access the i-th element within our indexes-argument:

    expr = Expression.Property(expr, "MyProperty");
    expr = Expression.ArrayIndex(expr, Expression.ArrayIndex(indexesArgument, Exression.Constant(0));
    expr = Expression.Property(expr, "AnotherProperty");
    expr = Expression.ArrayIndex(expr, Expression.ArrayExpression(indexesArgument, Expression.Constant(1));
    

    The Expression.Constant(0) leads to an ArrayIndexExpression of the first element within indexes, Expression.Constant(1) to the second one accordingly.

    Now after having compiled the expression-tree we can call the delegate to access the second int-value for AnotherProperty of the first instance within MyProperty:

    ClassA a = new ClassA 
    { 
        MyProperty = new[] { new ClassB 
        { 
            AnotherProperty = new[] { 1, 4 }
        }
    };
    int result = f(x, new[] { 0, 1 });