为什么Func<>和Expression<Func<>>可以互换?为什么其中一个在我的情况下有效?

6
我有一个数据访问类,花费了我一些时间才得以工作。对于我的应用程序,我需要获取不同类型的SQL Server表,其中WHERE子句仅通过列名称不同:有些列是read_time,其他列是ReadTime,还有其他列是LastModifiedTime。因此,我想传递WHERE子句,这样我就不需要为50个不同的表创建新方法。它看起来很简单,也可以工作,但我不明白其中的一些东西。
带有Expression<>作为参数的此方法有效:
internal List<T> GetObjectsGreaterThanReadTime<T>(Expression<Func<T, bool>> whereClause) where T : class
{
    Table<T> table = this.Database.GetTable<T>();
    IEnumerable<T> objects = table.Where(whereClause);

    return objects.ToList();
}

现在,我一直尝试以下方法(下面),但它会在最后一行(ToList())卡住。首先,为什么这个可以编译?我的意思是,为什么Expression和Func可以互换作为参数?然后,为什么Expression可用,而Func版本却卡住了?

注意:上述方法和此方法之间唯一的区别是方法参数(Expression vs. Func)。

internal List<T> GetObjectsGreaterThanReadTime<T>(Func<T, bool> whereClause) where T : class
{
    Table<T> table = this.Database.GetTable<T>();
    IEnumerable<T> objects = table.Where(whereClause);

    return objects.ToList();
}

3
这个回答本身连同答案一起,对于一些“表达式树有什么意义?”风格的问题是一个非常好的回应。+1 问答。 - James Wiseman
1个回答

12

Expression版本调用Queryable.Where生成一个表达式树,该表达式树(被ToList枚举时)被转换为SQL,并在数据库服务器上执行。 假设数据库服务器将利用基于筛选条件的索引,以避免读取整个表。

Func版本调用Enumerable.Where,当它被ToList枚举时加载整个表格(你所感受到的挂起),然后对内存中的对象运行筛选条件。


啊啊啊啊啊啊啊啊,太好了。非常有道理。谢谢! - Bob Horn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接