我一直在努力学习更多关于使用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"));
工作正常。可以告诉我,我做错了吗?
答案 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。