I was writing a IQueryable friendly replacement for WebGrid and I came to a halt around the part where I have to order the results by column name passed as a string. I managed to achieve my goal, but I don't like the resulting code so I hoped that someone could give me a hint how to improve it.
I wrote an extension for IQueryable for ordering by string based on what I found here, however it did not work at first and was giving me an error that said (more or less) that Int32 cannot be converted to Object (at this point I was testing ordering by column name with a column of ids, that's why the error said Int32). The problematic line:
var mySortExpression = Expression.Lambda<Func<T, object>>(Expression.Property(param, columnName), param);
I've added a conversion based on what can be found at this page, but that didn't work either and I got an error that said that I cannot order by object class. Here is how it looked at this point:
var mySortExpression = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(param, columnName), type), param);
So I figured out that I need to provide a sortable type in this line:
var mySortExpression = Expression.Lambda<Func<T, type>>(Expression.Property(param, columnName), param);
And rewritten the whole thing as follows:
public static IQueryable<T> OrderByString<T>(this IQueryable<T> query, string columnName)
{
var elementType = typeof(T);
var param = Expression.Parameter(elementType, "x");
var prop = elementType.GetProperty(columnName);
Type type = Nullable.GetUnderlyingType(prop.PropertyType);
if (type == null)
{
type = prop.PropertyType;
}
if (type.Equals(typeof(string)))
{
var mySortExpression = Expression.Lambda<Func<T, string>>(Expression.Property(param, columnName), param);
return query.OrderBy(mySortExpression);
}
if (type.Equals(typeof(char)))
{
var mySortExpression = Expression.Lambda<Func<T, char>>(Expression.Property(param, columnName), param);
return query.OrderBy(mySortExpression);
}
if (type.Equals(typeof(int)))
{
var mySortExpression = Expression.Lambda<Func<T, int>>(Expression.Property(param, columnName), param);
return query.OrderBy(mySortExpression);
}
if (type.Equals(typeof(float)) || type.Equals(typeof(double)))
{
var mySortExpression = Expression.Lambda<Func<T, double>>(Expression.Property(param, columnName), param);
return query.OrderBy(mySortExpression);
}
// This last part won't work but I left it so that it can compile (all routes need to return value etc.)
var mySortExpression1 = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(param, columnName), type), param);
return query.OrderBy(mySortExpression1);
}
This actually works, but all those repetitions don't look too good. Is there any way to improve this code?