IQueryable.OrderBy получает ключевое выражение селектора Expression<Func<TSource,TKey>>. IQueryable.Single получает выражение сравнения Expression<Func<TSource,bool>>.
Могу ли я преобразовать Expression<Func<TSource,TKey>> и значение TKey в Expression<Func<TSource,bool>>? Например, если у меня есть выражение выбора ключа x => e => e.Id, мне нужно выражение сравнения x => e => e.Id == value.
Я написал этот метод:
public Expression<Func<TEntity, bool>> KeyComparator(TKey key) =>
Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(KeySelector, Expression.Constant(key)))
Это делает компилятор счастливым. Я могу написать что-то вроде someQueryable.Single(KeyComparator(key)). Но когда он запускается, я получаю эту ошибку:
Бинарный оператор Equal не определен для типов System.Func`2[TSource,System.Int32] и System.Int32.
...где TSource - мое настоящее имя класса. Кажется, это говорит о том, что сравнение на равенство не определено для int и int. Хм?
Но как? Скажем, у меня есть дерево выражений вроде x => x.SomeIntegerKey, что бы вы сделали? Итак, вы хотите дополнительно иметь значение, а затем превратить его в x => x.SomeIntegerKey == yourDesiredValue или подобное?
Вы можете объединить два выражения, средство доступа к свойству; x => x.Prop и оператор, который сравнивает этот тип и возвращает bool; y => y == 0 в x => x.Prop == 0. Но вам нужно будет объяснить, что вы пытаетесь сделать и почему.
Смысл аргумента, который вы передаете OrderBy, заключается в том, что из каждого элемента в списке вы генерируете значение, а затем сортируете список по этим значениям. Если значение, которое вы создаете, имеет тип bool, то у вас есть то, что вы просите. Дело в том, что вы задаете этот вопрос по причине, которая на самом деле не имеет смысла, учитывая вашу ссылку на Single. Как было предложено выше, вам необходимо предоставить ПОЛНОЕ и ЯСНОЕ объяснение проблемы.
@JeppeStigNielsen Да, именно так.
@jmcilhinney Проблема очень проста: я хочу написать выражение селектора ключей и вывести из него выражение сравнения ключей, потому что DRY. Это в абстрактном классе, где разработчику нужно только написать выражение селектора ключа и пару других вещей, и он бесплатно получает несколько тысяч строк сгенерированного кода.





Итак, вы хотите преобразовать выражение в предикат, который сравнивает TKey (то, что оценивает выражение) с другим заданным TKey.
Вы должны получить Тело лямбда-выражения, которого не хватает в вашем коде, чтобы создать == выражение. Вы не можете сравнивать само лямбда-выражение с TKey. Body относится ко всему, что находится справа от => лямбды.
Вы также должны включить исходные параметры лямбды при помещении нового выражения == в Expression.Lambda.
public static Expression<Func<TSource, bool>> Convert<TSource, TKey>(
Expression<Func<TSource, TKey>> expr,
TKey key
) => Expression.Lambda<Func<TSource, bool>>(
Expression.Equal(expr.Body, Expression.Constant(key)),
expr.Parameters
);
Пример:
Console.WriteLine(Convert((String s) => s.Length, 1));
// s => (s.Length == 1)
Я думаю, что это приближает меня на шаг, но результат непереводим. Мой expr похож на o => o.CountryId, и в сообщении об ошибке говорится, что выражение 'o' непереводимо.
@KevinKrumwiede Compile может перевести. Не уверен, почему EF не может. пожимает плечами
Я написал тестовый контроллер в качестве минимального примера и подтвердил, что 1) это правильный ответ и 2) что-то еще в моем коде мешает EF его перевести, потому что он отлично работает в моем тестовом контроллере.
Эти типы никак не связаны. Ни
OrderBy, ниSingle. Например, каким будет результат, если(Foo x) => x.SomeStringPropertyпреобразовать в выражение, которое принимаетFooи возвращаетbool, учитывая строку"Bar"?