【问题标题】:Inheriting the equality comparer继承相等比较器
【发布时间】:2008-12-04 13:02:47
【问题描述】:

我有一个客户类。

public class Customer
{
    private string _id;
    private string _name;
    // some more properties follow 

我继承了 EqualityComparer 表单 MyEqualityComparer(of Customer)。
我打算在 LINQ 查询中使用它。
MyEqualityComparer 用于两个对象之间的部分检查。
如果 customer.id 和 customer.name 匹配,我将对象视为平等。

public class MyComparer : System.Collections.Generic.EqualityComparer<Customer>
{
    public override bool Equals(Customer x, Customer y)
    {
        if (x.Id == y.Id && x.Name == y.Name)
            return true;
        else
            return false;
    }

    public override int GetHashCode(Customer obj)
    {
        return string.Concat(obj.Id,obj.Name).GetHashCode();
    }

}

我提到了generating hashcode
我不太确定连接字符串并将其用作哈希码。
这是我想要做的安全和健全的事情吗?

【问题讨论】:

    标签: c# .net linq


    【解决方案1】:

    请参阅this question on hashcodes,了解基于多个字段返回一个哈希码的非常简单的方法。

    话虽如此,我自己不会从EqualityComparer&lt;T&gt; 派生 - 我只是直接实现IEqualityComparer&lt;T&gt;。除了实现非泛型 IEqualityComparer 之外,我不确定 EqualityComparer&lt;T&gt; 在这里真正给你带来了什么价值。

    还有几件事:

    • 您应该在 Equals 中处理无效性
    • 您现在的 Equals 代码可以简化为:

      return x.Id == y.Id && x.Name == y.Name;
      

    Equals 的更完整实现可能是:

    public override bool Equals(Customer x, Customer y)
    {
        if (object.ReferenceEquals(x, y))
        {
            return true;
        }
        if (x == null || y == null)
        {
            return false;
        }
        return x.Id == y.Id && x.Name == y.Name;
    }
    

    【讨论】:

    • 小错误 - 在与 null 比较之前,您需要将 x 和 y 转换为对象。见msdn.microsoft.com/en-us/library/ms173147
    • 是否有理由更喜欢使用三个returns 而不是一个可返回的逻辑表达式?
    • @NetMage:当天唯一的偏好 :) 我个人喜欢条件运算符,但我知道有些人觉得它更难阅读。
    • 我以为你不需要条件运算符,只需 &amp;&amp;|| :)
    【解决方案2】:

    您应该从可能的“碰撞”的角度来看待它,例如当两个不同的对象获得相同的哈希码时。这可能是“1,2any”和“12, any”这样的对的情况,对中的值是“id”和“name”。如果您的数据无法做到这一点,那么您就可以开始了。否则,您可以将其更改为:

    return obj.Id.GetHashCode() ^ obj.Name.GetHashCode();
    

    【讨论】:

    • 不要忘记空检查 Id 和 Name
    • 不幸的是,在很多情况下使用 XOR 会产生冲突。见stackoverflow.com/questions/263400/…。在名称/ID 的情况下可能没问题,但总的来说这不是一个好主意。
    【解决方案3】:

    Resharper(来自 JetBrains 的出色重构插件)认为它应该是:

    public override int GetHashCode(Customer obj)
    {
        unchecked
        {
            return ((obj.Id != null ? obj.Id.GetHashCode() : 0) * 397) 
                ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
        }
    }
    

    我不得不承认,我几乎总是让 Resharper 为我生成相等和哈希码实现。我已经对他们的实现进行了大量测试,发现它与我手写的任何东西一样好,如果不是更好的话。所以我通常会采用我不必键入的实现。

    【讨论】:

    • 除了素数之外,还有什么理由选择 397 吗?
    • 我认为它只是为了将哈希码的第一部分放在最终结果的较高位中。 Resharper 曾经使用 29。我不能说我知道是否有可靠的理论,或者它是否只是通过实验选择的。
    猜你喜欢
    • 2012-12-02
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    • 2017-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多