Неявное приведение не происходит в дереве выражений - PullRequest
5 голосов
/ 31 мая 2011

Я столкнулся со сценарием, в котором мне нужно отсортировать список пользовательских типов по различным свойствам на основе входных данных. С помощью нескольких статей я смог придумать общую реализацию с использованием модульного тестирования LINQ.During. Один из тестов не удался, потому что неявное преобразование происходило при создании лямда-выражения с использованием дерева выражений.

Ниже я поместил пример кода, чтобы понять проблему (не уверен, почему форматирование не получалось правильным, извините за это)

static class ExtensionMethods
{
 public static IEnumerable<TSource> Sort<TSource>(this IEnumerable<TSource> unSortedList, Func<TSource, object> selector, bool isAscending)
    {
       return isAscending ? unSortedList.OrderBy(selector) :                 unSortedList.OrderByDescending(selector);
}   
}

class Program
{

    class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    static void Main(string[] args)
    {
        var unOrderedStudents = new List<Student>
                           {
                               new Student{ Name="A", Age=20},
                               new Student{Name = "B", Age=19}
                           };


        //This Works
        var sortUsingLamda = unOrderedStudents.Sort<Student>(stud => stud.Age, true);


        //Exception - Expression of type 'System.Int32' cannot be used for return type 'System.Object'
        var sortUsingExpressionTree = unOrderedStudents.Sort<Student>( GetSortFunc<Student>("Age"), true);

        Console.WriteLine("Press any key to continue");
        Console.ReadLine();
    }



    private static Func<T, object> GetSortFunc<T>(string sortColumn)
    {
        var param = Expression.Parameter(typeof(T), "entity");

        var propertyExpression = Expression.Property(param, sortColumn);

        var boxingExpression = Expression.Convert(propertyExpression, typeof(object));

        return Expression.Lambda<Func<T, object>>(propertyExpression, param).Compile();

        //after adding Convert expression issue got fixed
        //return Expression.Lambda<Func<T, object>>(boxingExpression, param).Compile();

    }
} 

В методе Main, когда я пытаюсь передать делегат Func напрямую в метод расширения Sort, он работает, но не работает с деревом выражений.

Я обнаружил похожую проблему , но это говорит о параметрах ограниченного типа. Обе проблемы одинаковы? Может кто-нибудь помочь мне понять проблему.

Ответы [ 3 ]

5 голосов
/ 31 мая 2011

Вам нужно использовать коробочную версию (вы в настоящее время создаете boxingExpression, но вместо этого основываете свой окончательный запрос на propertyExpression):

return Expression.Lambda<Func<T, object>>(boxingExpression, param).Compile();

Re, почему это не так 't неявный - просто - это здесь нет неявного приведения;Expression! = C #.Бокс является нетривиальной операцией, и для Expression API требуется определенный узел в дереве.

2 голосов
/ 31 мая 2011

У вас есть прототипы GetSortFunc , возвращающие экземпляр Func <> , который возвращает объект. Поэтому ваша задача - обеспечить, чтобы сгенерированное вами дерево выражений приводило к объекту.

Хотя int неявно преобразуется в объект в C # под капотом, он упаковывается. Вот почему вам нужно боксерское выражение в вашем коде, и поэтому вам нужно сгенерировать лямбда-выражение, используя выражение, полученное вами из Expression.Convert . Лучший способ думать об этом - когда вы используете деревья выражений, вы должны четко указывать все преобразования и не думать об этом с точки зрения того, как бы вы написали код на C #.

1 голос
/ 31 мая 2011

У вас есть параметр Func<TSource, object> selector.Это означает, что у вас есть функция, получает объект TSource и возвращает object.Поэтому вам нужно скомпилировать выражение boxingExpression и вернуть результат:

     return Expression.Lambda<Func<T, object>>(boxingExpression, param).Compile();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...