OfType<TResult>() 缺乏优化

Lack of optimisation in OfType<TResult>()

我正在查看 System.Linq.Enumerable.OfType<TResult>() 的源代码:

    public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source) {
        if (source == null) throw Error.ArgumentNull("source");
        return OfTypeIterator<TResult>(source);
    }

    static IEnumerable<TResult> OfTypeIterator<TResult>(IEnumerable source) {
        foreach (object obj in source) {
            if (obj is TResult) yield return (TResult)obj;
        }
    }

如果IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;结果是一个非空值,而TResult是一个值类型,那么就不会有任何null值,因此不需要枚举通过每个值。

您可以 return 来源作为 IEnumerable<TResult>

他们有什么理由不这样设计方法吗?:

        public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source)
        {
            if (source == null) throw new ArgumentNullException("source");

            IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
            if (typedSource != null)
            {
                if (typeof(TResult).IsValueType)
                {
                    return typedSource;
                }
            }

            return OfTypeIterator<TResult>(source);
        }

如果源包含大量元素,只需检查源是否只包含值类型,就可以节省大量时间。

编辑:

我知道一些初学者开发人员还没有了解 value/reference 类型,也不知道值类型不能是 null。 我可以想象初学者会了解到 OfType<T>() 过滤掉 null 值的情况,并认为它适用于 int 的列表。 对于这些情况,优化将使程序员受益(尽管不如学习 value/reference 类型那么多)。

我的想法来自 Jon Skeet's blog

只有实施该方法的 Microsoft 人员才能确定地告诉您为什么要这样实施。然而……

请务必注意, 提出的替代方案在很多有趣的场景中都不起作用。与可能调用 OfType<T>() 的场景相比,它在何时起作用非常有限。

的确,它 在调用者不应该首先调用 OfType<T>() 的情况下起作用。毕竟,如果对象实际上已经是 IEnumerable<TResult> 类型,那么按类型 filter 源是没有意义的。调用者应该已经足够了解源的实际类型,以了解是否真的需要这种过滤。他们当然不应该因为删除 null 值的副作用而调用 OfType<T>()

那么,为什么要引入 "optimization" 只优化一开始就不应该编写的代码呢?这与通常的优化指南大相径庭。首要规则之一是关注 常见 案例。优化不常见的情况通常是浪费代码,尤其是在库中,当所讨论的特定不常见情况涉及 错误 代码时尤其如此。