Как вывести TResult из фактического типа? - PullRequest
2 голосов
/ 05 мая 2010

Я использую Entity Framework, ASP.NET и C # 3.5 Я заимствовал следующий код, чтобы сделать возможной сортировку, используя sortExpression из GridView вместо свойства объекта:

    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);
    }

Проблема в том, что LINQ to Entities не поддерживает приведение к объекту. Вместо Func мне нужен фактический тип возвращаемого значения вместо объекта. Я разобрался, как это сделать:

    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);
    }

Проблема в том, что если у меня есть Int32, он не будет приведен к объекту, который по-прежнему является возвращаемым типом. Я работал над этим так:

    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);
    }

Это, однако, больше не компилируется. Ошибка:

Аргументы типа для метода 'System.Linq.Enumerable.OrderByDescending (System.Collections.Generic.IEnumerable, System.Func)' не могут быть выведены из использования. Попробуйте указать аргументы типа явно.

Проблема в том, что я не хочу явно указывать аргументы типа.

Кто-нибудь знает, как обойти это или как-то сделать вывод типа TResult из "propertyType"?

1 Ответ

1 голос
/ 05 мая 2010

Используемый подход здесь , с уточнением здесь , должен делать то, что вам нужно. По необходимости он использует рефлексию, чтобы сделать кишки посередине, но это работает. Также обратите внимание, что Expression.GetFuncType и Expression.GetActionType могут избежать некоторой работы в вашем подходе.

...