5

重要问题不是“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 并转换结果,这似乎是整个事情中最明智的部分。

现在,此方法的效果是返回一个表达式,该表达式告诉提供者忽略返回类型不等于 TResult 或其子类型之一的任何值。但我看不到上述步骤实际上是如何实现这一点的。它似乎正在创建一个表示返回 IQueryable<TResult> 的方法的表达式,并使该方法的主体简单地成为整个源表达式,而无需查看类型。是否只是期望 IQueryable 提供程序只会默默地不返回任何不属于所选类型的记录?

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

4

1 回答 1

5

它不是null作为方法传入 - 它是作为“目标表达式”传入的,即它调用该方法的内容。这是 null 因为OfType是静态方法,所以它不需要目标。

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

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

这就是Queryable一般的工作方式 - 基本上它让提供者将整个查询表达式视为表达式树。这就是它的全部意义——当要求提供者将其翻译成真实的代码时,这就是魔法发生的地方。

Queryable自己不可能完成这项工作——它不知道提供者代表什么样的数据存储。OfType在不知道数据存储是 SQL、LDAP 还是其他东西的情况下,它怎么能得出这样的语义呢?我同意这需要一段时间才能让你头脑清醒:)

于 2009-09-17T16:49:16.447 回答