例如考虑:
var hset = new HashSet<int>();
// Fill the hset.
var enumerable = hset as IEnumerable<int>;
bool enumerable.Contains(0);
LINQ是否使用HashSet具有Contains
的高效实现这一事实,或者它是否完全按照预期对枚举器进行操作?
我问的原因是我正在处理的组件有许多属性IEnumerable<T>
,但是之前的开发人员总是转换他用来创建可枚举对象的任何数据结构在将数据分配给属性之前的数组。我不确定这是好的做法还是完全浪费时间。
答案 0 :(得分:7)
有一些优化,而Contains就是其中之一。
现在,当我们拥有Microsoft公共符号服务器时,我们可以在有疑问时查看代码。这是.NET Framework 4中Enumerable.Contains
的实现:
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value)
{
ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null) return collection.Contains(value);
return Contains<TSource>(source, value, null);
}
该方法将源代码转换为ICollection<T>
,并在成功时使用它的Contains
方法。由于HashSet<T>
实现ICollection<T>
,因此使用的实际方法为HashSet<T>.Contains
。这是好的,因为与阵列O(N)相比,它是O(1)操作。
换句话说,首先转换为数组会对性能造成伤害:复制操作首先需要时间,然后实际查找效率会降低,O(N),因为Contains方法需要查看所有的数组的元素。
通常,在浏览Enumerable.cs时,通常会使用此模式:大多数方法尝试使用方法的ICollection版本,这样做会带来好处。
答案 1 :(得分:1)
Linq扩展方法Contains
有一个实现ICollection<>
的枚举的快捷方式。由于HashSet<>
实现了ICollection<>
,因此它会进行有效的查找。
<强> Documented in MSDN 强>
如果源类型实现ICollection(Of T),则调用该实现中的Contains方法以获取结果。否则,此方法确定source是否包含指定的元素。
使用Reflector验证
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value)
{
ICollection<TSource> is2 = source as ICollection<TSource>;
if (is2 != null)
{
return is2.Contains(value);
}
return source.Contains<TSource>(value, null);
}
答案 2 :(得分:0)
这取决于。在诉诸“最小公分母”实现(仅使用IEnumerable<T>
接口的实现)之前,某些方法会检查特定的接口。
例如,Count
确实检查了ICollection
和ICollection<T>
,以便在诉诸于逐个统计所有元素之前利用(可能)O(1)计数之一。
似乎driis's answer Contains
ICollection<T>
的方式相同,检查HashSet<T>
(IEnumerable<T>
实施)。
现在,我不清楚你在这里的意思:
[之前的开发人员]总是将他用来创建可枚举对象的数据结构转换为数组,然后再将其分配给属性。
如果您的意思是您的馆藏实际上已复制到数组中,以便HashSet<T>
公开,那么您肯定 获得Contains
班级{{1} } 方法;你得到了数组的(因为T[]
数组确实实现了ICollection<T>
,虽然这真的不比天真的方法好。)
答案 3 :(得分:0)
linq Contains
扩展方法会检查类型并执行相关操作。如果可枚举实现ICollection<T>
,则将调用其ICollection<T>.Contains()
方法。如果不是,则使用foreach
枚举枚举,直到找到指定的项目。
由于HashSet<T>
实现ICollection<T>
,将调用Contains
方法。
答案 4 :(得分:0)
如果源类型实现ICollection,则调用该实现中的Contains方法以获取结果。否则,此方法确定source是否包含指定的元素。