How do I infer TResult from the actual type?
I am using Entity Framework, ASP.NET and C # 3.5 I used the following code to make sorting possible using sortExpression from GridView instead of object property:
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 doesn't support casting to an entity. Instead of Func, I need an actual return type instead of an 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);
}
Now the problem is that if I have an Int32 it won't get passed to the object, which is still the return type. I worked around it this way:
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, no longer compiles. Error:
The type arguments for the "System.Linq.Enumerable.OrderByDescending (System.Collections.Generic.IEnumerable, System.Func)" method cannot be retired. Try to specify type arguments explicitly.
The problem is that I don't want to explicitly list the type arguments.
Does anyone know how to get around this or somehow infer the TResult type from "propertyType"?
a source to share
The approach used here , with clarification here , should do what you need. It uses reflection as needed to make the guts in the middle, but it works. Also note that Expression.GetFuncType
, and Expression.GetActionType
can avoid some of the actions in your approach.
a source to share