Queryable.OfType如何工作?

时间:2009-09-17 16:43:18

标签: linq expression-trees oftype

重要问题不在于“Queryable.OfType 做什么,这是”我在那里看到的代码是如何实现的?“

反思Queryable.OfType,我看到(经过一些清理):

    public static IQueryable<TResult> OfType<TResult>(this IQueryable source)
    {
        return (IQueryable<TResult>)source.Provider.CreateQuery(
            Expression.Call(
                null, 
                ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(
                    new Type[] { typeof(TResult) }) ,
                    new Expression[] { source.Expression }));
    }

那么让我看看我是否已经这样做了:

  1. 使用反射来获取对当前方法(OfType)的引用。
  2. 使用MakeGenericMethod将当前方法的类型参数更改为完全相同的东西,创建一个完全相同的新方法。
  3. 该新方法的参数不是source而是source.Expression。哪个不是IQueryable,但我们会将整个事情传递给Expression.Call,所以没关系。
  4. 调用Expression.Call,将null作为方法(奇怪?) 实例并将克隆方法作为参数传递。
  5. 将结果传递给CreateQuery并投射结果,这似乎是整个事情的最佳部分。
  6. 现在,此方法的效果是返回一个表达式,该表达式告诉提供程序省略返回类型不等于TResult或其子类型之一的任何值。但我看不出上面的步骤是如何实现这一目标的。它似乎创建了一个表达式,表示返回IQueryable&lt; TResult&gt;的方法,并使该方法的主体只是整个源表达式,而不需要查看类型。是否只是希望IQueryable提供者只是默默地不返回任何不属于所选类型的记录?

    上面的步骤在某种程度上是不正确的,或者我只是没有看到它们如何导致在运行时观察到的行为?

1 个答案:

答案 0 :(得分:5)

它没有传递null作为方法 - 它将它作为“目标表达式”传递,即它正在调用方法。这是null,因为OfType是静态方法,所以它不需要目标。

调用MakeGenericMethod的重点是GetCurrentMethod()会返回开放版本,即OfType<>而不是OfType<YourType>

Queryable.OfType本身不是意味着包含任何省略返回任何值的逻辑。这取决于LINQ提供商。 Queryable.OfType的要点是构建表达式树以包含对OfType的调用,这样当LINQ提供程序最终必须将其转换为其本机格式(例如SQL)时,它知道OfType 1}}被召唤。

这就是Queryable一般工作的方式 - 基本上它让提供者将整个查询表达式看作表达式树。这就是它的意思 - 当要求提供者将其转换为真实代码时,那是神奇发生的地方。

Queryable本身不可能完成工作 - 它不知道提供者代表什么类型的数据存储。如果不知道数据存储是SQL,LDAP还是其他什么,它怎么能提出OfType的语义?我同意这需要一段时间才能让你的头脑清醒:)