I am using the Entity Framework, ASP.NET and C#3.5 I borrowed the following code to make sorting possible using a sortExpression from a GridView instead of the property of an entity:
public static IEnumerable<T> Sort<T>(this IEnumerable<T> source, string sortExpression)
{
string[] sortParts = sortExpression.Split(' ');
var param = Expression.Parameter(typeof(T), string.Empty);
var property = Expression.Property(param, sortParts[0]);
var sortLambda = Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param);
if (sortParts.Length > 1 && sortParts[1].Equals("desc", StringComparison.OrdinalIgnoreCase))
{
return source.AsQueryable<T>().OrderByDescending(sortLambda);
}
return source.AsQueryable<T>().OrderBy(sortLambda);
}
The problem is that LINQ to Entities does not support casting to object. Instead of Func, I need the actual return type instead of object. I worked out how to do it:
public static IEnumerable<T> Sort<T>(this IEnumerable<T> source, string sortExpression)
{
string[] sortParts = sortExpression.Split(' ');
var param = Expression.Parameter(typeof(T), string.Empty);
var property = Expression.Property(param, sortParts[0]);
// NEW CODE HERE
Type propertyType = property.Type;
Type lambdaType = typeof(Func<,>).MakeGenericType(typeof(T), propertyType);
var sortLambda = Expression.Lambda<Func<T, object>>(Expression.Convert(property, propertyType), param);
//var sortLambda = Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param);
if (sortParts.Length > 1 && sortParts[1].Equals("desc", StringComparison.OrdinalIgnoreCase))
{
return source.AsQueryable<T>().OrderByDescending(sortLambda);
}
return source.AsQueryable<T>().OrderBy(sortLambda);
}
The problem now is that if I have an Int32, it will not cast to object, which is still the return type. I worked around it like this:
public static IEnumerable<T> Sort<T>(this IEnumerable<T> source, string sortExpression)
{
string[] sortParts = sortExpression.Split(' ');
var param = Expression.Parameter(typeof(T), string.Empty);
var property = Expression.Property(param, sortParts[0]);
// New code here
Type propertyType = property.Type;
Type lambdaType = typeof(Func<,>).MakeGenericType(typeof(T), propertyType);
// NEWEST CODE HERE
var sortLambda = Expression.Lambda(lambdaType, Expression.Convert(property, propertyType), param);
//var sortLambda = Expression.Lambda<Func<T, object>>(Expression.Convert(property, propertyType), param);
//var sortLambda = Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param);
if (sortParts.Length > 1 && sortParts[1].Equals("desc", StringComparison.OrdinalIgnoreCase))
{
return source.AsQueryable<T>().OrderByDescending(sortLambda);
}
return source.AsQueryable<T>().OrderBy(sortLambda);
}
This however does not compile any longer. The error is:
The type arguments for method 'System.Linq.Enumerable.OrderByDescending(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
The problem is that I do not want to specify the type arguments explicitly.
Does anyone know how to work around this or anyhow infer the TResult type from "propertyType"?