Реализация IEqualityComparer <T> для объекта с двумя свойствами в С#

У меня есть случай, когда мне нужно захватить кучу элементов на разных, но мой источник представляет собой набор объектов с двумя свойствами, например:

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() для свойства, но поскольку я сравниваю два свойства, я немного теряю, что делать. Я делаю что-то неправильно или пропуская что-то действительно очевидное?

Ответ 1

Вы можете реализовать 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;

Ответ 2

Я бы хотел связать следующие сообщения о переполнении стека, хотя вопрос уже ответил.

GetHashCode -

Почему важно переопределить GetHashCode, когда метод Equals переопределен?

Кроме того, в приведенном выше ответе Тим Шмельтер говорит 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 -

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;
    }
}