Передача в Выражении к запросу Linq ведет себя по-другому в зависимости от синтаксиса, используемого, и интересно почему дело обстоит так.
Скажем, у меня есть эта очень родовая функция
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
Следующая реализация работает как ожидалось
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
{
return (from c in _ctx.Companies.Where(whereClause) select c);
}
Но эта следующая реализация не компилирует (Делегат 'Система. Func' не берет 1 аргумент),
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
{
return (from c in _ctx.Companies where whereClause select c);
}
Очевидно, я могу просто использовать первый синтаксис, но я просто задавался вопросом, почему компилятор не рассматривает где ключевое слово то же как Где расширение?
Спасибо, Thomas
Синтаксис для выражения запроса, содержащего предложение , где
есть (упрощение полной грамматики)
from identifier in expression where boolean-expression select expression
, где предложение
не логическое выражение. Чтобы процитировать это, вы должны сказать
from c in _ctx.Companies where whereClause.Compile()(c) select c;
Обратите внимание, что если whereClause
было Func
, вы могли бы уйти с
from c in _ctx.Companies where whereClause(c) select c;
Обратите внимание, что
from x in e where f
переведено «механически» компилятором в
(from x in e).Where(x => f)
я говорю «механически», потому что он выполняет это преобразование без какого-либо семантического анализа для проверки правильности вызовов методов и т. д. Этот этап наступает позже, после того как все выражения запроса переведены в выражения вызова метода LINQ.
В частности,
from c in _ctx.Companies where whereClause select c
переведено на
_ctx.Companies.Where(c => whereClause).Select(c)
, что явно бессмысленно.
Причина, по которой
from c in _ctx.Companies.Where(whereClause) select c
является допустимым, заключается в том, что IEnumerable
имеет перегрузку, принимающую Func
, и существует неявное преобразование из Выражение
в Func
.
Фактически вы можете сократить все это до:
private IEnumerable<Company>
GetCompanies(Expression<Func<Company, bool>> whereClause)
{
return _ctx.Companies.Where(whereClause);
}
При использовании синтаксиса LINQ код в предложении , где
переведено в Выражение <>
, которое представляет собой кодовое дерево. Когда вы принимаете Expression
, вы говорите, что ваш метод принимает кодовое дерево, которое компилятор преобразует из кода C #.
Поскольку у вас уже есть кодовое дерево, вы должны передать его напрямую методу Where ()
, а не использовать синтаксис LINQ.
Разница в том, что в sql-методе where ожидается выражение, которое оценивается в bool. Но в методе Where тип выражения может быть делегатом.
чтобы заставить второй работать, можно изменить на whereClause.Compile()(c)
или изменить параметр на Func
и whereClause(c)