调用IEnumerable.Cast <t>()会将基础类型更改为其他类型,还是保留基础类型?</t>

时间:2014-04-08 08:44:31

标签: c# linq linq-to-objects

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

如果我这样做:_set.Cast<TInterface>().Contains(obj, comparer);(其中T实施TInterface),我是否会失去O(1)的{​​{1}}权益?

换句话说 - HashSet<T>是否会将基础类型(在这种情况下为.Cast<T>())更改为其他内容,或保留基础类型?

3 个答案:

答案 0 :(得分:5)

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


也就是说,让我们更详细地了解您的具体情况:

Cast<T>方法如下(来自reference-source):

  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<>是一个协变接口,因此该测试将针对您的用例传递(假设具体类型实现接口类型)并且哈希集将直接返回 - 这是一件好事,因为仍有希望正在使用的内部哈希表。

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

 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)。

答案 1 :(得分:1)

_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();

答案 2 :(得分:0)

Cast方法返回一个IEnumerable,因此Contains方法将对IEnumerable而不是HashSet进行操作。所以我认为你放弃了HashSet的好处。你为什么不在比较中进行演员表?