我正在寻找现实世界中的最佳实践,了解其他人如何使用复杂的领域实现解决方案。
IEqualityComparer<T>
时,暂停一下思考是否可以将这个类实现为 IEquatable<T>
。如果一个 Product
应该总是通过 ID 进行比较,只需要定义它相等于 ID,这样就可以使用默认的比较器。StringComparer
中。IEquatable<T>
的方式定义。这包括由其他人定义的类和编译器生成的类(特别是匿名类型,默认情况下使用属性逐个比较)。class ProductByIdComparer : GenericEqualityComparer<ShopByProduct>
{
public ProductByIdComparer()
: base((x, y) => x.ProductId == y.ProductId, z => z.ProductId)
{ }
}
在使用方面,应尽可能利用比较器。例如,不要在每个用作字典键的字符串上调用ToLower()
(其逻辑将散布在应用程序中),而应声明字典使用不区分大小写的StringComparer
。对于接受比较器的LINQ运算符也是如此。但请始终考虑类应具有内在的可比性行为而不是在外部定义。
public class GenericEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, Boolean> _comparer;
private Func<T, int> _hashCodeEvaluator;
public GenericEqualityComparer(Func<T, T, Boolean> comparer)
{
_comparer = comparer;
}
public GenericEqualityComparer(Func<T, T, Boolean> comparer, Func<T, int> hashCodeEvaluator)
{
_comparer = comparer;
_hashCodeEvaluator = hashCodeEvaluator;
}
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
{
return _comparer(x, y);
}
public int GetHashCode(T obj)
{
if(obj == null) {
throw new ArgumentNullException("obj");
}
if(_hashCodeEvaluator == null) {
return 0;
}
return _hashCodeEvaluator(obj);
}
#endregion
}
var comparer = new GenericEqualityComparer<ShopByProduct>((x, y) => x.ProductId == y.ProductId);
var current = SelectAll().Where(p => p.ShopByGroup == group).ToList();
var toDelete = current.Except(products, comparer);
var toAdd = products.Except(current, comparer);
var comparer = new GenericEqualityComparer<ShopByProduct>(
(x, y) => { return x.ProductId == y.ProductId; },
(x) => { return x.Product.GetHashCode()}
);
obj.GetHashCode();
是错误的。IComparer<T>
一样,查找算法可能接受一个 IEqualityComparer<T>
。这个列表经常使用这个接口,所以你可以使用a.Substract(b)或其他这些好用的函数。
只要记住:如果你的对象不返回相同的哈希码,那么Equals方法就不会被调用。
obj.GetHashCode()
是有意义的。请参见我帖子中的链接:https://dev59.com/LHVD5IYBdhLWcg3wI4CM#4679491 - Peet Britsobj.GetHashCode()
回退。例如比较器:(s1,s2)=>s1.ToLower().Equals(s2.ToLower())
返回true
,而默认的string.GetHashCode()
返回false
! - ulrichb