调用 IEnumerable.Cast<T>() 是将底层类型更改为其他类型,还是保留底层类型?



>假设我有ISet<T> _set = new HashSet<T>();

现在,如果我这样做:_set.Cast<TInterface>().Contains(obj, comparer);T实现TInterface),我是否失去了HashSet<T>O(1)好处?

换句话说 - .Cast<T>() ing是将基础类型(在本例中为HashSet<T>)更改为其他类型,还是保留基础类型?

从逻辑上讲,HashSet<T>使用基于创建它的比较器的哈希逻辑的内部哈希表,因此当然不可能使用不同的比较器对其进行元素包含测试并期望 O(1) 性能。


也就是说,让我们更详细地看一下您的特定方案:

Cast<T>方法如下所示(来自参考来源):

  public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) {
            IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
            if (typedSource != null) return typedSource;
            if (source == null) throw Error.ArgumentNull("source");
            return CastIterator<TResult>(source);
        }

如您所见,如果源实现IEnumerable<TResult>它只是直接返回源。由于IEnumerable<>是一个协变接口,这个测试将通过你的用例(假设具体类型实现了接口类型),哈希集将直接返回 - 这是一件好事,因为仍然有希望使用其内部哈希表。

但是,您使用的包含的重载如下所示:

 public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
        {
            if (comparer == null) comparer = EqualityComparer<TSource>.Default;
            if (source == null) throw Error.ArgumentNull("source");
            foreach (TSource element in source)
                if (comparer.Equals(element, value)) return true;
            return false;
        }

如您所见,它总是循环通过集合进行线性搜索,即 O(n)。

因此,无论如何,整个操作都将是O(n)。

_set.Cast<TInterface>()将返回一个IEnumerable<TInterface>,因此_set.Cast<TInterface>().Contains(obj, comparer);不会调用HashSet.Contains,而是调用Enumerable.Contains扩展方法。

所以很明显你不再O(1)手术了。

如果您需要O(1)则需要再次创建HashSet

   var newSet = new HashSet(_set.Cast<TInterface>(),comparer);
   newSet.Contains();
Cast 方法返回一个 IEnumerable

,因此 Contains 方法将对 IEnumerable 而不是 HashSet 进行操作。所以我认为你会失去HashSet的好处。你为什么不做比较中的演员表?

相关内容

  • 没有找到相关文章

最新更新