Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access nested properties with dynamic lambda using Linq.Expression

Let's assume that I have two classes:

class person
{
    int ID
    string name
    Address address
}
class address
{
    int ID
    string street
    string country
}

These classes are more or less given, they are mapped via nHibernate to be honest :)

In a grid (datatables.net as base) I would like to have a type-independent sorting.

Therefore I created a lambda expression:

  var param = Expression.Parameter(typeof(T), typeof(T).Name);
  var sortExpression = Expression.Lambda<Func<T, object>>
                              (Expression.Convert(Expression.Property(param, "Property to sort"), typeof(object)), param);

If I pass Person as Type T and replace the "Property to sort" with "name" it works fine (creates a correct lambda). If the Property to sort is "address.street" it won't work, throw me the following error:

Property 'address.street' is not defined for type 'person'

I see only one solution so far, but not clear enough... I would try to split the string which contains the Property-Name (split by .)

Can anyone give a better solution? I need to add the sortExpression to an IQueryable object query.OrderBy(sortExpression).

Not sure if my title is clear, please go ahead and correct it.

Thanks in advance.

like image 774
griti Avatar asked Nov 04 '09 14:11

griti


2 Answers

What is not clear?

You have to split it and then use:

Expression.Property(Expression.Property(param, "address"), "street")
like image 90
LukLed Avatar answered Nov 15 '22 23:11

LukLed


Here's a more generic version of LukLed's answer:

    protected MemberExpression NestedExpressionProperty(Expression expression, string propertyName)
    {
        string[] parts = propertyName.Split('.');
        int partsL = parts.Length;

        return (partsL > 1) 
            ? 
            Expression.Property( 
                NestedExpressionProperty(
                    expression, 
                    parts.Take(partsL - 1)
                        .Aggregate((a, i) => a + "." + i)
                ), 
                parts[partsL - 1]) 
            :
            Expression.Property(expression, propertyName);
    }

You can use it like this:

var paramExpression = Expression.Parameter(this.type, "val");
var firstProp = NestedExpressionProperty(paramExpression,"address.street");
like image 43
DShook Avatar answered Nov 15 '22 23:11

DShook