LINQ 方法和 IEnumerableT 与 IQueryableT

关于 IEnumerable<T> 的 LINQ 扩展方法采用实际方法 1 ,是否匿名方法:

//C#
Func<int,bool> fn = x => x > 3;
var list = new List<int>() {1,2,3,4,5,6};
var query = list.Where(fn);

'VB.NET
Dim fn = Function(x As Integer) x > 3
Dim list = New List From {1,2,3,4,5,6};
Dim query = list.Where(fn);

或命名方法(明确定义为类的一部分的方法):

//C#
class Program {
    bool LessThan4(int x) {
        return x < 4;
    }

    void Main() {
        var list = new List<int>() {1,2,3,4,5,6};
        var query = list.Where(LessThan4);
    }
}

'VB.NET
Class Program
    Function LessThan4(x As Integer) As Boolean
        Return x < 4
    End Function
    Sub Main
        Dim list = New List From {1,2,3,4,5,6};
        Dim query = list.Where(AddressOf LessThan4)
    End Sub
End Class

从理论上讲,可以解析方法的 IL ,弄清楚方法尝试做什么,并将该方法的逻辑应用于任何底层数据源,而不仅仅是内存中的对象。但解析 IL 不适合胆小的人。

幸运的是,.NET 提供了 IQueryable<T> 接口,以及 System.Linq.Queryable 的扩展方法。这些扩展方法采用表达式树 - 表示代码的数据结构 - 而不是实际方法,然后 LINQ 提供程序可以解析 2 并转换为更合适的形式以查询底层数据源。例如:

//C#
IQueryable<Person> qry = PersonsSet();

// Since we're using a variable of type Expression<Func<Person,bool>>, the compiler 
// generates an expression tree representing this code
Expression<Func<Person,bool>> expr = x => x.LastName.StartsWith("A");
// The same thing happens when we write the lambda expression directly in the call to 
// Queryable.Where

qry = qry.Where(expr);

'VB.NET
Dim qry As IQueryable(Of Person) = PersonSet()

' Since we're using a variable of type Expression(Of Func(Of Person,Boolean)), the compiler 
' generates an expression tree representing this code
Dim expr As Expression(Of Func(Of Person, Boolean)) = Function(x) x.LastName.StartsWith("A")
' The same thing happens when we write the lambda expression directly in the call to 
' Queryable.Where

qry = qry.Where(expr)

如果(例如)此查询针对 SQL 数据库,则提供程序可以将此表达式转换为以下 SQL 语句:

SELECT *
FROM Persons
WHERE LastName LIKE N'A%'

并针对数据源执行它。

另一方面,如果查询针对 REST API,则提供程序可以将同一表达式转换为 API 调用:

http://www.example.com/person?filtervalue=A&filtertype=startswith&fieldname=lastname

基于表达式定制数据请求有两个主要好处(而不是将整个集合加载到内存中并在本地查询):

  • 底层数据源通常可以更有效地查询。例如,LastName 上可能有一个索引。将对象加载到本地内存并查询内存会失去效率。
  • 数据可以在传输之前进行整形和缩小。在这种情况下,数据库/ Web 服务只需要返回匹配的数据,而不是从数据源中获得的整个人员集。

注释
1.从技术上讲,它们实际上并不采用方法,而是委托指向方法的实例 。但是,这种区别在这里无关紧要。
2.这就是 “ LINQ to Entities 无法识别方法’System.String ToString()‘方法 错误的原因*,并且此方法无法转换为商店表达式。* ” LINQ 提供程序(在本例中为 Entity Framework 提供程序)不知道如何解析和转换对 ToString 的调用到等效的 SQL。 **