问题 在C#中具有两个属性的对象上实现IEqualityComparer


我有一个案例,我需要抓取一堆不同的项目,但我的源是一个具有两个属性的对象的集合,如下所示:

public class SkillRequirement
{
    public string Skill { get; set; }
    public string Requirement { get; set; }
}

我尝试获得如下集合:

SkillRequirementComparer sCom = new SkillRequirementComparer();

var distinct_list = source.Distinct(sCom);

我试图实现一个 IEqualityComparer<T> 为此,但我倒霉了 GetHashCode() 方法。

Comparer的类:

public class SkillRequirementComparer : IEqualityComparer<SkillRequirement>
{
    public bool Equals(SkillRequirement x, SkillRequirement y)
    {
        if (x.Skill.Equals(y.Skill) && x.Requirement.Equals(y.Requirement))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public int GetHashCode(SkillRequirement obj)
    {
        //?????
    }
}

通常我会用 GetHashCode() 在一个属性上,但因为我在两个属性上进行比较,我有点不知所措。我做错了什么,或者遗漏了一些非常明显的东西?


7947
2018-05-21 10:24


起源

使用时要小心 GetHashCode() 这是从可变领域派生的!如果将对象放在散列集合中,则更改其中一个字段 - ouch。我建议让它一成不变。 - Matthew Watson
属性的值是从数据库开始的,其中列不允许空值,在将对象添加到源列表之前还检查空字符串或空字符串,因此不需要考虑:^) - Felix Weir


答案:


你可以实现 GetHashCode 以下列方式:

public int GetHashCode(SkillRequirement obj)
{
    unchecked
    {
        int hash = 17;
        hash = hash * 23 + obj.Skill.GetHashCode();
        hash = hash * 23 + obj.Requirement.GetHashCode();
        return hash;
    }
}

  本来 来自J.Skeet

如果属性可以 null 你应该避免 NullReferenceException,例如:

int hash = 17;
hash = hash * 23 + (obj.Skill ?? "").GetHashCode();
hash = hash * 23 + (obj.Requirement ?? "").GetHashCode();
return hash;

10
2018-05-21 10:27



(实际上它最初来自Josh Bloch;) - Matthew Watson
不是个好主意。那些属性是可变的。 - Ufuk Hacıoğulları
@UfukHacıoğulları:你能指出你的反对意见吗? - Tim Schmelter
@TimSchmelter我猜他担心在将对象放入散列容器后改变字段。 - Matthew Watson
哇谢谢!你知道它是如何工作的吗?我从来没有遇到过 unchecked 关键词之前......:^) - Felix Weir


我想链接以下堆栈溢出帖子虽然问题已经回答了..

GetHashCode的  -

为什么在重写Equals方法时重写GetHashCode很重要?

此外,Tim Schmelter在上述答案中说 the properties can be null you should avoid a NullReferenceException

int hash = 17;
hash = hash * 23 + (obj.Skill ?? "").GetHashCode();
hash = hash * 23 + (obj.Requirement ?? "").GetHashCode();
return hash;

的IEqualityComparer  -

  1. 使用IEqualityComparer和Equals / GethashCode Override有什么区别
  2. GetHashCode在.NET中IEqualityComparer中的作用是什么?
  3. 如何以及何时在C#中使用IEqualityComparer

IEquatable  - IEquatable与重写Object.Equals()之间有什么区别?

等于  - 重载等于的指南()

class TwoDPoint : System.Object
{
    public readonly int x, y;

    public TwoDPoint(int x, int y)  //constructor
    {
        this.x = x;
        this.y = y;
    }

    public override bool Equals(System.Object obj)
    {
        // If parameter is null return false.
        if (obj == null)
        {
            return false;
        }

        // If parameter cannot be cast to Point return false.
        TwoDPoint p = obj as TwoDPoint;
        if ((System.Object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public bool Equals(TwoDPoint p)
    {
        // If parameter is null return false:
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public override int GetHashCode()
    {
        //return x ^ y;
    }
}

1
2018-01-28 11:27