объединить метод MethodCallExpression для MemberExpression

2

Я хочу создать следующее выражение Linq, используя дерево выражений:

var result2 = soldiers.OrderByDescending(soldier => soldier.Ranks.OrderBy(r=> r.Date).FirstOrDefault().Date).ToArray() ;

Модели указаны в конце вопроса

Я пытался сделать следующее:

ParameterExpression pe = Expression.Parameter(typeof(Soldier), "soldier");

// e.g soldier.ranks
MemberExpression rank = Expression.Property(pe, "ranks");

ParameterExpression nestedParams = Expression.Parameter(typeof(Rank), "rank");

var dateProperty = typeof(Rank).GetProperty("Date");

// e.g rank.Date
MemberExpression nestedExpression= Expression.MakeMemberAccess(nestedParams, dateProperty);

// e.g rank => rank.date
var orderByExp = Expression.Lambda<Func<Rank, DateTime?>>(nestedExpression, nestedParams);

MethodCallExpression orderByCallExpression2 = Expression.Call(
typeof(Queryable),
"OrderByDescending",
 new Type[] { typeof(Rank), typeof(DateTime?) },
 rank, ***// i suspect the problem is in this line #110***
 orderByExp);

Но была допущена следующая ошибка:

System.InvalidOperationException: 'No generic method 'OrderByDescending' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic. '

Как я уже писал в комментариях к коду, я подозреваю, что проблема возникает becuase линии 110. Я попытался сцепить метод OrderBy на soldier.ranks собственности. Но, возможно, из-за того, что 'soldier.ranks - это MemberExpression вместо MethodCallExpression или Queryable, я не смог выполнить это действие заранее.

Я использовал обе ссылки в качестве ссылки, но смог найти что-то похожее на мою проблему. * https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/how-to-use-expression-trees-to-build-dynamic-queries

* qaru.site/questions/531514/...

модели:

public class Soldier
{
    public Rank Rank {
        get {
            return this.Ranks.OrderByDescending(m => m.Date).FirstOrDefault();
        }
    }

    public ICollection<Rank> Ranks { get; set; }
}

public class Rank
{
    public int Id { get; set; }

    public DateTime? Date { get; set; }
}

Спасибо,

Теги:
linq
lambda
expression-trees

1 ответ

3
Лучший ответ

Я подозреваю, что проблема возникает из-за линии 110

MethodCallExpression orderByCallExpression2 = Expression.Call(
typeof(Queryable),
"OrderByDescending",
 new Type[] { typeof(Rank), typeof(DateTime?) },
 rank, ***// i suspect the problem is in this line #110***
 orderByExp);

Нет, проблема в Queryable 3 строки выше:

typeof(Queryable),

Неважно, какой именно тип rank выражения (член, вызов метода и т.д.), Важно то, каков тип результата этого выражения (т.е. Expression.Type). И тип soldier.Ranks является ICollection<Rank> - определенно не IQueryable<Rank>, следовательно, исключение.

Но, как мы знаем, ICollection<T> наследует (является) IEnumerable<T>, поэтому oldier.Ranks.OrderBy фактически является вызовом Enumerable.OrderBy а не Queryable.OrderBy.

С учетом вышесказанного просто измените Queryable на Enumerable в вышеупомянутой строке, и эта конкретная проблема будет решена.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню