使用具有IEnumerable的Lambda表达式树

时间:2010-03-07 20:41:18

标签: c# linq tree ienumerable expression

我一直在努力学习更多关于使用Lamba表达式树的知识,因此我创建了一个简单的例子。这是代码,如果作为C#程序粘贴,它在LINQPad中工作。

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; }
}

这会导致以下错误:

无法从用法中推断出方法'System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable,System.Func)'的类型参数。尝试显式指定类型参数。

但是如果我用main替​​换main中的第一行:

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

工作正常。可以告诉我,我做错了吗?

4 个答案:

答案 0 :(得分:5)

Enumerable.Where方法需要Func<T, bool>,而不是Expression<Func<T, bool>>。也许你会对Queryable.Where感到困惑,{{1}}确实将表达式作为参数...在你的情况下你不需要表达式,你只需要一个可以对序列中的每个项执行的委托。表达式的目的(大部分)被分析并转换为其他东西(例如SQL),以执行对外部数据源的查询

答案 1 :(得分:2)

NameContains的返回类型从Expression<Func<User, Bool>>更改为Func<User, Bool>。在这种情况下,不需要返回Expression,您实际上想要返回已编译的委托。构成lambda的表达式和lambda(它是委托)本身之间存在差异。

如果将lambda发送到方法中,则该方法可以将lambda接受为表达式,也可以接受为已编译的委托类型,具体取决于您在参数中指定的内容。如果传入的参数类型是表达式,则可以发送看似委托的内容,但是,如果该方法需要委托,则必须为其提供已编译的委托,而不仅仅是表达式。话虽这么说,你也可以这样做:

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

将编译表达式,并返回Func<User, Bool>

答案 2 :(得分:0)

Lambda表达式可以被视为代码(委托)或数据(表达式树)

在您的示例中,您尝试将lambda表达式视为代码。

您可以使用Expression&lt;&gt;当您想将lambda表达式视为数据时声明。

你为什么要这样做?

以下是“Linq In Action”一书的引用,

“表达式树可以在运行时提供给工具,使用它们来指导 他们的执行或将其转换为其他内容,例如SQL的情况 LINQ to SQL。“

使用表达式树允许您获取lambda表达式并将其转换为数据,这就是Linq to SQL的工作方式,它采用lambda表达式或查询运算符或查询表达式并将它们转换为SQL。您当然可以在转换为sql后查看和修改创建的表达式树。

答案 3 :(得分:0)

Expression和Func&lt; ...&gt;之间存在巨大差异,Func是一个可以直接调用它的纯委托,表达式是一个数据结构,包含有关lambda表达式或Linq语法的信息的表达式信息(例如,从列表中的x开始,其中x.Id = 1选择x)。表达式不能直接调用它必须先编译,表达式用于将表达式从一种方式转换为另一种方式,如Link To Sql,它将表达式转换为Sql语句,这是改变NameContains返回类型的最佳方法使用Linq To Objects时使用表达式的方法,但是当使用Linq To Sql时,可以同时使用Expression或func。