对于实现大量的IEqualityComparers有些懒惰,并且考虑到我无法轻松编辑被比较对象的类实现,我使用了以下内容,意在与Distinct()和Except()扩展方法一起使用 . :
public class GenericEqualityComparer<T> : IEqualityComparer<T>
{
Func<T, T, bool> compareFunction;
Func<T, int> hashFunction;
public GenericEqualityComparer(Func<T, T, bool> compareFunction, Func<T, int> hashFunction)
{
this.compareFunction = compareFunction;
this.hashFunction = hashFunction;
}
public bool Equals(T x, T y)
{
return compareFunction(x, y);
}
public int GetHashCode(T obj)
{
return hashFunction(obj);
}
}
看起来很不错,但每次真的需要一个哈希函数吗?我知道哈希码用于将对象放入存储桶中 . 不同的桶,对象不相等,并且不调用相等 .
如果GetHashCode返回相同的值,则调用equals . (来自:Why is it important to override GetHashCode when Equals method is overridden?)
所以可能出现问题,例如(我听到很多程序员惊恐地尖叫),GetHashCode返回一个常量,强制调用Equal?
5 回答
没有什么会出错,但在基于散列表的容器中,在进行查找时,您将从大约O(1)到O(n)性能 . 简单地将所有内容存储在List中并蛮力地搜索它以查找满足相等性的项目 .
如果一个常见的用例是根据一个属性比较对象,你可以添加一个额外的构造函数并实现并调用它:
这将自动使用属性实现的哈希 .
编辑:一个更有效和更强大的实现启发了我的Marc评论:
你的表现将会消失 .
Distinct
和Except
在集合数据结构上实现时是高效的操作 . 通过提供一个恒定的哈希值,你基本上破坏了这个特性,并使用线性搜索强制简单算法 .您需要查看这是否适用于您的数据量 . 但对于稍微大一些的数据集,差异将会很明显 . 例如,
Except
将从预期时间O(n)增加到O(n²),这可能是一个大问题 .而不是提供常量,为什么不调用对象自己的
GetHashCode
方法?它可能没有给出特别好的值,但它不能比使用常量更差,并且除非重写对象的GetHashCode
方法以返回错误的值,否则仍将保留正确性 .在CodeProject上找到了这个 - A Generic IEqualityComparer for Linq Distinct()做得很好 .
使用案例:
通用IEqualityComparer
试试这段代码:
示例:collection = collection.Except(ExistedDataEles,new GenericCompare(x => x.Id)) . ToList();