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" 只优化一开始就不应该编写的代码呢?这与通常的优化指南大相径庭。首要规则之一是关注 常见 案例。优化不常见的情况通常是浪费代码,尤其是在库中,当所讨论的特定不常见情况涉及 错误 代码时尤其如此。
我正在查看 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" 只优化一开始就不应该编写的代码呢?这与通常的优化指南大相径庭。首要规则之一是关注 常见 案例。优化不常见的情况通常是浪费代码,尤其是在库中,当所讨论的特定不常见情况涉及 错误 代码时尤其如此。