【问题标题】:Using Lambda Expressions trees with IEnumerable将 Lambda 表达式树与 IEnumerable 一起使用
【发布时间】:2010-03-07 20:41:18
【问题描述】:

我一直在尝试了解有关使用 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 中的第一行替换为:

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

它工作正常。请告诉我我做错了什么?

【问题讨论】:

    标签: c# linq tree ienumerable expression


    【解决方案1】:

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

    【讨论】:

    • 是的,这正是我做错的。我想我仍然需要在这个主题上做更多的阅读,以便更好地理解它。我的另一个示例是使用 IQueryable 并且工作正常,当我使用 IEnumerable 列表构建一个新示例时它不起作用。我不确定 Expression 关键字的含义。
    • 将 lambda 表达式视为委托或表达式树这一事实取决于上下文。在您的代码中,您将返回类型声明为 Expression,这告诉编译器将 lambda 表达式视为表达式树,而不是可执行委托。顺便说一句,表达式不是关键字,它是一种类型
    • D'oh ... 键入不是关键字。谢谢托马斯。
    • 我在另一个 stackoverflow 帖子中找到了这篇文章,该帖子更详细地解释了表达式树。现在我了解了我所做的和仅使用 Func 之间的根本区别,我将更详细地研究表达式树。 blogs.msdn.com/charlie/archive/2008/01/31/…
    【解决方案2】:

    NameContains 的返回类型从Expression&lt;Func&lt;User, Bool&gt;&gt; 更改为简单的Func&lt;User, Bool&gt;。在这种情况下,不需要返回表达式,您实际上想要返回已编译的委托。组成 lambda 的表达式与 lambda(它是一个委托)本身之间存在差异。

    如果您将 lambda 发送到方法中,则该方法可以接受 lambda 作为表达式或编译的委托类型,具体取决于您在参数中指定的内容。如果传入的参数类型是一个表达式,你可以发送一个看起来像委托的东西,但是,如果方法需要一个委托,你必须给它一个编译的委托,而不仅仅是一个表达式。话虽如此,您还可以执行以下操作:

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

    这将编译表达式,并返回 Func&lt;User, Bool&gt;

    【讨论】:

      【解决方案3】:

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

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

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

      您为什么要这样做?

      这是来自 Book Linq In Action 的引述,

      " 表达式树可以在运行时提供给工具,使用它们来指导 它们的执行或将它们翻译成其他东西,例如 SQL 的情况下 LINQ to SQL。”

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

      【讨论】:

      • 好的,这有助于我更好地理解这一点。我可以看到为什么我处理 LINQ to SQL 和从表返回的 IQueryable 的另一个示例现在可以使用 reurn 类型 Expression。
      【解决方案4】:

      Expression 和 Func 之间有很大的不同<...>,Func 是一个纯委托,您可以直接调用它,表达式是一个数据结构,包含有关表达式的信息,例如有关 lambda 表达式或 Linq 语法的信息 (例如,从 x.Id = 1 的列表中的 x 选择 x)。表达式不能直接调用,必须先编译,表达式用于将表达式从一种方式转换为另一种方式,例如将表达式转换为 Sql 语句的 Link To Sql,最好的方法是更改​​ NameContains 的返回类型Method to Func insted of expression cuz you are working with Linq To Objects,但在使用 Linq To Sql 时,您可以同时使用 Expression 或 func。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-12-03
        • 2023-02-01
        • 1970-01-01
        • 2011-05-31
        • 1970-01-01
        • 2012-01-15
        • 1970-01-01
        相关资源
        最近更新 更多