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的扩展方法同理。

浙公网安备 33010602011771号