Создать Generic Expression из имени свойства строки

У меня есть переменная с именем sortColumn, которая содержит текст столбца, который я хочу отсортировать результат запроса. У меня также есть общий репозиторий, который принимает в качестве параметра выражение, которое содержит поле, которое я хочу сортировать. Кажется, я не могу получить от имени свойства строки выражение.

Итак, общий репозиторий, который у меня есть, содержит следующий метод

public IEnumerable<TEntity> Get<TOrderBy>(Expression<Func<TEntity, bool>> criteria,
                                          Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex,
                                          int pageSize,
                                          bool isAssendingOrder = true,
                                          EnumDeletePolicy deletePolicy = EnumDeletePolicy.ExcludeDeleted)

Обратите внимание на второй параметр для этого Get is Expression-Func-TEntity, TOrderBy. Как я уже упоминал, у меня есть переменная с именем sortColumn, которая содержит строку для свойства моего объекта TEntity. Мне нужно преобразовать эту строку в выражение, которое я могу передать методу Get.

Вот что я имею прямо сейчас.

        var parameter = Expression.Parameter(typeof(IContract));
        var memberExpression = Expression.Property(parameter, data.SortColumn);
        var lambdaExpression = Expression.Lambda(memberExpression, parameter);

Что создает объект типа LambdaExpression. Фактическим типом этого выражения LambdaExpression является строка Expression-Func-IContract (или любой тип sortColumn свойства). Если я вызову метод Get и передаю это выражение LambdaExpression и явно применил его к типу Expression, тогда он будет работать нормально. Проблема в том, что я не знаю, что такое тип выражения, это может быть строка, int, int?, и т.д. Все зависит от типа свойства, определенного в свойстве sortColumn.

Можете ли вы помочь мне сделать этот последний прыжок в правильном выражении?

Изменить на основе предложений Marc: У меня почти есть эта работа, фактически основанная конкретно на вопросе, который она работает, но у меня есть 1 проблема.

IContract, который является типом Entity, который я запрашиваю, фактически наследуется от IRelationship. Если я укажу поле из интерфейса IContract, то работает вышеописанный код. Если я укажу поле из интерфейса IRelationship, следующая строка не будет выполнена.

        var memberExpression = Expression.Property(parameter, data.SortColumn);

Если я попробую что-то вроде ниже, чтобы я захватил MemberExpression из IRelationship, но построил Lambda на основе IContract, я получаю сообщение об ошибке из репозитория.

        var parameter = Expression.Parameter(typeof(IRelationship));
        var memberExpression = Expression.Property(parameter, data.SortColumn);
        var orderBy = Expression.Lambda(memberExpression, Expression.Parameter(typeof(IContract)));

Ошибка, которую я получаю, это "Параметр" не был связан в указанном выражении запроса LINQ to Entities.

Окончательное выражение, чтобы заставить его работать, это

        var parameter = Expression.Parameter(typeof(IContract));
        var memberExpression = Expression.Property(parameter, typeof(IRelationship), data.SortColumn);
        var orderBy = Expression.Lambda(memberExpression, parameter);

Итак, мне нужно было указать средний параметр в строке memberExpression, чтобы сказать, что в унаследованном интерфейсе отношения для свойства

Ответы

Ответ 1

Вам нужно использовать правильную общую перегрузку, что означало, что вам приходилось использовать MakeGenericMethod; однако вы также можете использовать dynamic, чтобы избежать необходимости использовать MakeGenericMethod здесь, например (в данном случае через Where, но важным моментом является то, как он работает):

IQueryable<Foo> source = new[] { new Foo { Bar = 123 } }.AsQueryable();
Expression<Func<Foo,bool>> typed =  x=>x.Bar == 123;

LambdaExpression untyped = typed;
IQueryable<Foo> filtered = Queryable.Where(source, (dynamic)untyped);

Примечание. Вы не можете использовать методы расширения здесь, поэтому вам нужно использовать Queryable.*.

Для примера OrderBy, используя ваш код:

var parameter = Expression.Parameter(typeof(Foo));
var memberExpression = Expression.Property(parameter, "Bar");
var lambdaExpression = Expression.Lambda(memberExpression, parameter);
LambdaExpression untyped = lambdaExpression;

IQueryable<Foo> sorted = Queryable.OrderBy(source, (dynamic)untyped);

var all = sorted.ToArray();

Повторите редактирование:

var parameter = Expression.Parameter(typeof(IRelationship));
var memberExpression = Expression.Property(
    Expression.Convert(parameter, typeof(IContract)), data.SortColumn);
var orderBy = Expression.Lambda(memberExpression, parameter);