Используя деревья Лямбда-выражений с IEnumerable

Я пытался узнать больше об использовании деревьев выражений Lamba и таким образом, я создал простой пример. Вот код, это работает в LINQPad, если вставляется в как программа C#.

void Main()
{
    IEnumerable<User> list = GetUsers().Where(NameContains("a"));
    list.Dump("Users");
}

// Methods
public IEnumerable<User> GetUsers()
{
    yield return new User{Name = "andrew"};
    yield return new User{Name = "rob"};
    yield return new User{Name = "chris"};
    yield return new User{Name = "ryan"};
}

public Expression<Func<User, bool>> NameContains(string namePart)
{
    return u => u.Name.Contains(namePart);
}

// Classes
public class User
{
    public string Name { get; set; }
}

Это приводит к следующей ошибке:

Аргументы типа для метода 'Система. Linq. Счетный. Где (Система. Наборы. Универсальный. IEnumerable, Система. Func)', не может быть выведен из использования. Попытайтесь определить аргументы типа явно.

Однако, если я просто заменяю первой строкой в основном с этим:

IEnumerable<User> list = GetUsers().Where(u => u.Name.Contains("a"));

Это хорошо работает. Может сказать мне, что я делаю неправильно?

9
задан Loathian 7 March 2010 в 20:41
поделиться

3 ответа

Метод Enumerable.Where принимает Func, а не Expression>. Возможно, вы путаете с Queryable.Where, который действительно принимает выражение в качестве параметра... В вашем случае вам не нужно выражение, вам просто нужен делегат, который может быть выполнен против каждого элемента в последовательности. Цель выражений (в основном) - быть проанализированными и переведенными во что-то другое (например, SQL), чтобы выполнить запрос к внешнему источнику данных

.
5
ответ дан 4 December 2019 в 23:06
поделиться

Измените тип возвращаемого значения NameContains с Expression > на просто ] Func <Пользователь, Bool> .В этой ситуации нет необходимости возвращать Expression, вы действительно хотите вернуть скомпилированный делегат. Есть разница между выражением, составляющим лямбду, и самой лямбдой (которая является делегатом).

Если вы отправляете лямбду в метод, метод может принимать лямбда либо как выражение, либо как скомпилированный тип делегата, в зависимости от того, что вы указываете в параметрах. Если тип входящего параметра является выражением, вы можете отправить что-то похожее на делегата, однако, если метод ожидает делегата, вы должны передать ему скомпилированный делегат, а не просто выражение. При этом вы также можете сделать что-то вроде:

 var certainUsers = GetUsers().Where(NameContains("a").Compile());

Которая скомпилирует выражение и вернет Func .

2
ответ дан 4 December 2019 в 23:06
поделиться

Лямбда-выражения можно рассматривать как код (делегаты) или как данные (деревья выражений)

В вашем примере вы пытаетесь обработать лямбда-выражение как код.

Вы можете использовать объявление Expression <>, если хотите обрабатывать лямбда-выражение как данные.

Зачем вам это нужно?

Вот цитата из книги Linq In Action,

«Деревья выражений могут быть переданы инструментам во время выполнения, которые используют их, чтобы направлять их выполнение или преобразовывать их во что-то другое, например SQL в случае LINQ to SQL."

Использование деревьев выражений позволяет вам взять лямбда-выражение и преобразовать его в данные, именно так работает Linq в SQL, он принимает лямбда-выражение, операторы запроса или выражения запроса и преобразует их в SQL. Вы, конечно, можете просмотреть и изменить созданное дерево выражений после преобразования в sql.

0
ответ дан 4 December 2019 в 23:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: