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"?

+2


a source to share


1 answer


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.



+1


a source







All Articles