NPehrsson
NPehrsson

Reputation: 1548

Build an Lambda expression from an propertypath

Hi lets say I have an property path looking like this

We can say that I have an article that has an Vat and Vat has an Value. Now I want to use Linq to sort a list using that property path How can I build that lambda expression when I have "Vat.Value" in a string and I want the following result

list.Order(x => x.Vat.Value)

I will not always know the types of Vat and Value, sometimes its only x.Name I'm out for.

Upvotes: 1

Views: 1115

Answers (3)

NPehrsson
NPehrsson

Reputation: 1548

I fixed it with an extension method. The approach to use an propertypath now is for example

var orderedArticles = articles.OrderBy("Vat.Value");

instead of

var orderedArticles = articles.OrderBy(x => x.Vat.Value)

Extension methods:

private static Func<T, TReturnType> GetLambda<T, TReturnType>(IEnumerable<string> propertyNames)
{
    var rootParameterExression = Expression.Parameter(typeof(T));

    Expression expression = rootParameterExression;
    foreach (var propertyName in propertyNames)
    {
        expression = Expression.Property(expression, propertyName);
    }
    return Expression.Lambda<Func<T, TReturnType>>(expression, rootParameterExression).Compile();
}

public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> queryable, string propertyPath)
{
    var propertyPathList = propertyPath.Split(Convert.ToChar("."));
    Type propertyType = typeof(T);
    foreach (var propertyName in propertyPathList)
    {
        propertyType = propertyType.GetProperty(propertyName).PropertyType;
    }

    if(propertyType == typeof(decimal))
    {
        var lambda = GetLambda<T, Decimal>(propertyPathList);
        return queryable.OrderBy(lambda);
    }
    var lamda = GetLambda<T, object>(propertyPathList);
    return queryable.OrderBy(lamda);
}

Upvotes: 2

jrwren
jrwren

Reputation: 17908

Is there a reason you cannot use the existing LINQ Dynamic Query library, which has overloads which take strings?

http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

It might be doing the same thing you just wrote, but its code that you don't have to maintain and may have some optimizations.

Upvotes: 1

Chris Marinos
Chris Marinos

Reputation: 965

I'm not sure I totally understand the question, but something like this looks like what you want. Note that I'd probably refactor the lambda into a helper method in production for clarity. Also note that using reflection like this may be a significant performance hit depending on how large your collection is.

[Test]
public void OrderByUsingReflection()
{
    var values = new[] 
    {
        new { Vat = new { Value = "two"}},
        new { Vat = new {Value = "one"}},
    };

    var result = values.OrderBy(x =>
    {
        var vat = x.GetType().GetProperty("Vat").GetValue(x, null);
        return vat.GetType().GetProperty("Value").GetValue(vat, null);
    });

    Assert.AreEqual(result.ToList()[0], values[1]);
    Assert.AreEqual(result.ToList()[1], values[0]);
}

Upvotes: 0

Related Questions