65.9K
CodeProject is changing. Read more.
Home

Building OrderBy Lambda Expression from Property Name in C#

Sep 10, 2014

CPOL

1 min read

viewsIcon

49632

downloadIcon

233

Let's make a lambda expression from a property name of a particular entity, and use it for OrderBy shorting

Introduction

Here in this post, we are going to see how to make a lambda expression from a property name of a particular entity, and use it for OrderBy shorting for both IQueryable and IEnumerable sources.

Background

Let’s say we have a model.

public class Phone
{
    public double Price { get; set; }
    public string Brand { get; set; }
}

And we have a data source Db.Phones, and for regular OrderBy shorting by property, we use:

/*When using lambda expression*/
Db.Phones.OrderBy(x => x.Price).ToList();
Db.Phones.OrderBy(x => x.Brand).ToList();

Now, we want to do this shorting with property name only, rather than using lambda expression, like:

/*But we needed to do*/
Db.Phones.OrderBy("Price").ToList();
Db.Phones.OrderBy("Brand").ToList();

One interesting thing is the data source could be any among IQueryable or IEnumerable. So we have to consider both.

Db.Phones                    //source is IQueryable<Phone>
Db.Phones.AsEnumerable()    //source is IEnumerable<Phone>

Utility Class

Here is the utility class, which will be used to make lambda expression from a property name for a particular entity.

public static class Utility
{
    //makes expression for specific prop
    public static Expression<Func<TSource, object>> GetExpression<TSource>(string propertyName)
    {
        var param = Expression.Parameter(typeof(TSource), "x");
        Expression conversion = Expression.Convert(Expression.Property
        (param, propertyName), typeof(object));   //important to use the Expression.Convert
        return Expression.Lambda<Func<TSource, object>>(conversion, param);
    }

    //makes deleget for specific prop
    public static Func<TSource, object> GetFunc<TSource>(string propertyName)
    {
        return GetExpression<TSource>(propertyName).Compile();  //only need compiled expression
    }

    //OrderBy overload
    public static IOrderedEnumerable<TSource> 
    OrderBy<TSource>(this IEnumerable<TSource> source, string propertyName)
    {
        return source.OrderBy(GetFunc<TSource>(propertyName));
    }

    //OrderBy overload
    public static IOrderedQueryable<TSource> 
    OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
    {
        return source.OrderBy(GetExpression<TSource>(propertyName));
    }
}

Here are the two overloads for OrderBy to handle both IEnumerable<TSource> and IQueryable<TSource>.

Using the Code

Now let’s test the overloads:

List<Phone> orderedByPrice = null;
List<Phone> orderedByBrand = null;

/*When source is IQueryable*/
orderedByPrice = Db.Phones.OrderBy("Price").ToList();
orderedByBrand = Db.Phones.OrderBy("Brand").ToList();

/*When source is IEnumerable*/
orderedByPrice = Db.Phones.AsEnumerable().OrderBy("Price").ToList();
orderedByBrand = Db.Phones.AsEnumerable().OrderBy("Brand").ToList();

For a quick overview, check out https://dotnetfiddle.net/sEmFzq.

Limitations

  1. Yes, there could be something which I misunderstood or presented. So if you find anything, just let me know.
  2. I have tested this for simple properties (string Name, int Id, etc.) as I have shown here. But if we have complex properties like (Processor Processor; where processor has name, and we want to do order by Processor.Name), it may collapse.

Find the Visual Studio 2010 solution in the attachment.