My method receives all DataTables parameters to sort table by column clicked. I call this method from controller of each page list. I'm looking for a better way to do this like a generic method for all types: string, int, decimal, double, bool (nullable or not). But I can't find it.
My current code:
public List<T> OrderingList<T>(List<T> list, DataTablesParam model)
{
var iColumn = model.Order.FirstOrDefault().Column;
var property = typeof(T).GetProperty(model.Columns.ToArray()[iColumn].Data);
var param = Expression.Parameter(typeof(T));
var final = Expression.Property(param, property);
var isDirAsc = model.Order.FirstOrDefault().Dir.Equals("asc");
if (property.PropertyType == typeof(string))
{
var lambda = Expression.Lambda<Func<T, string>>(final, param).Compile();
return isDirAsc ? list.OrderBy(lambda).ToList() : list.OrderByDescending(lambda).ToList();
}
else if (property.PropertyType == typeof(int))
{
var lambda = Expression.Lambda<Func<T, int>>(final, param).Compile();
return isDirAsc ? list.OrderBy(lambda).ToList() : list.OrderByDescending(lambda).ToList();
}
else if (property.PropertyType == typeof(bool))
{
var lambda = Expression.Lambda<Func<T, bool>>(final, param).Compile();
return isDirAsc ? list.OrderBy(lambda).ToList() : list.OrderByDescending(lambda).ToList();
}
else if (property.PropertyType == typeof(decimal))
{
var lambda = Expression.Lambda<Func<T, decimal>>(final, param).Compile();
return isDirAsc ? list.OrderBy(lambda).ToList() : list.OrderByDescending(lambda).ToList();
}
else if (property.PropertyType == typeof(double))
{
var lambda = Expression.Lambda<Func<T, double>>(final, param).Compile();
return isDirAsc ? list.OrderBy(lambda).ToList() : list.OrderByDescending(lambda).ToList();
}
return list;
}
I want to do something like this: (But this code doesn't work)
public List<T> OrderingList<T>(List<T> list, DataTablesParam model)
{
var iColumn = model.Order.FirstOrDefault().Column;
var property = typeof(T).GetProperty(model.Columns.ToArray()[iColumn].Data);
var param = Expression.Parameter(typeof(T));
var final = Expression.Property(param, property);
var isDirAsc = model.Order.FirstOrDefault().Dir.Equals("asc");
var lambda = Expression.Lambda<Func<T, dynamic>>(final, param).Compile();
return isDirAsc ? list.OrderBy(lambda).ToList() : list.OrderByDescending(lambda).ToList();
}
Your suggested method almost works. You need to change two things in order to make it work:
dynamic
useobject
, since every type is anobject
.If you have a value type, you need a boxing operation, i.e. you must cast the value to object
(object)i
. This is done with a unary convert operation:Note also that final is declared explicitly as
Expression
, since the expression type might change from property to unary expression.Beyond just not being very generic, your solution also requires a lot of extra memory because you're copying the list with LINQ. You can avoid this using
List.Sort
.I would do:
It's works fine for me: (Thanks @Poke)
https://stackoverflow.com/a/31393168/5112444
My final method:
I found a better way to do this. I had to do 3 steps:
1 - Add the package "Linq Dynamic" in project:
2 - Import the package in Class:
3 - Order list by the string name of property:
It work perfectly for me.
You can just call the
Enumerable.OrderBy
method using reflection. That way, you don’t have to know the type at compile-time. To do that, you just need to get the method, and create a generic method using the property’s type:Note that I abstracted out the stuff about your model to keep this method generic enough. It can basically sort by any property on a list by just specifying the property name. Your original method would then look like this: