C# HashSet不要遍历或者使用泛型扩展方法

C#的接口 IEnumerable 定义了 GetEnumerator 方法,它的拓展方法是都是基于这个迭代器实现的。

当我们使用比如,First、Where等泛型方法时,会实例化一个迭代器 Enumerator 包含 属性Current,方法MoveNext()

    public interface IEnumerator
    {
        bool MoveNext();
        Object Current {get;}
        void Reset();
    }

  其中HashSet的MoveNext实现如下:

            public bool MoveNext() {
                if (version != set.m_version) {
                    throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
                }
          //遍历每一个slot
                while (index < set.m_lastIndex) {
                    if (set.m_slots[index].hashCode >= 0) {
                        current = set.m_slots[index].value;
                        index++;
                        return true;
                    }
                    index++;
                }
                index = set.m_lastIndex + 1;
                current = default(T);
                return false;
            }

  比如说对HashSet使用First()尝试获取第一个元素,那么它将会生成一个迭代器,从HashSet内部维护的 Slot[] 的 index=0 处开始查找,而由于HashSet的 Slot 是基于哈希算法计算索引位置的,其中的未被哈希命中的Slot都是默认值,也就是空值。这意味着当你调用First函数时,将会从 Slot[] 的头部一直找到第一个不为空的 Slot 进行返回,也就是对 Slot[] 进行了枚举,时间复杂度是O(n)而不是O(1),效率将极大降低。

其它IEnumerable的扩展方法同理。

posted @ 2022-10-30 13:30  崩溃大喵  阅读(209)  评论(0)    收藏  举报