【问题标题】:Lack of optimisation in OfType<TResult>()OfType<TResult>() 中缺乏优化
【发布时间】:2019-12-01 02:09:11
【问题描述】:

我在看System.Linq.Enumerable.OfType&lt;TResult&gt;()的源代码:

    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&lt;TResult&gt; typedSource = source as IEnumerable&lt;TResult&gt;; 产生非空值,而TResult 是值类型,则不能有任何null 值,因此无需枚举每个值。

您可以将源返回为IEnumerable&lt;TResult&gt;

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

        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);
        }

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

编辑:

我知道一些初学者还没有了解值/引用类型,也不知道值类型不能是null。 我可以想象初学者开发人员会知道OfType&lt;T&gt;() 过滤掉null 值的情况,认为它可以在ints 列表上工作。 在这些情况下,优化将使程序员受益(尽管不如学习值/引用类型那么多)。

我的想法来自Jon Skeet's blog

【问题讨论】:

  • 我在这里可能是错的,但这可能有用的唯一地方是当 T(源)== TResult 时。如果 TResult 是 ValueType 并且与 T 相同,为什么要使用 OfType ?不确定,这将如何实际优化 OfType 方法
  • 你从哪里得到这个实现?我记得不同的框架有不同的实现。例如 .Net Core 和 .NET 框架之间的不同
  • @M.kazemAkhgary 这是来自 GitHub 的源代码。
  • @AnuViswan:您可能在编译时不知道源代码的T。不要忘记这个(和Cast)的目标是IEnumerable,而不是IEnumerable&lt;T&gt;Cast 方法这样优化的。
  • 请注意,这在 TResult 是可空值类型的情况下不起作用 - 真正的 OfType 方法也会从中过滤掉空值。不过你可以很容易地解决这个问题。

标签: c# .net ienumerable


【解决方案1】:

只有实现该方法的 Microsoft 人员才能确切地告诉您为什么以这种方式实现它。不过……

请务必注意,您的建议的替代方案在很多有趣的场景中都不起作用。与可能调用 OfType&lt;T&gt;() 的场景相比,它的工作时间非常有限。

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

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

【讨论】:

  • 为什么开发人员不应该使用 OfType() 来摆脱空值?过滤掉它们的最佳方法是什么?
  • “为什么开发人员不应该使用 OfType() 去除空值?” -- 因为代码应该表达意图。调用OfType&lt;T&gt;() 表达的意图是“我只想要T 类型的对象”。确实,仅暗示非空,但这不是该方法的原因“过滤掉它们的最佳方法是什么?” -- where 子句是一种方法;循环中的 if 语句是另一个;如果你真的想要一个方法来做到这一点,编写你自己的NotNull&lt;T&gt;() 方法是微不足道的。您甚至可以将其限制为 where T : class 以获得更好的表现力。
猜你喜欢
  • 1970-01-01
  • 2019-09-01
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 2012-02-29
  • 2012-01-07
  • 2018-11-23
  • 2021-05-12
相关资源
最近更新 更多