수색…


비고

Equals 각 구현은 다음 요구 사항을 충족해야합니다.

  • 반사적 (Reflexive) : 객체는 그 자체로 동일해야합니다.
    x.Equals(x)true 반환 true .

  • 대칭 : x와 y를 비교하거나 x를 y와 비교하면 차이가 없습니다. 결과는 같습니다.
    x.Equals(y)y.Equals(x) 와 같은 값을 반환합니다.

  • 전이 : 한 객체가 다른 객체와 같고이 객체가 세 번째 객체와 같으면 첫 번째 객체는 세 번째 객체와 같아야합니다.
    if (x.Equals(y) && y.Equals(z))true 반환하면 x.Equals(z)true 반환 true .

  • 일관성 : 개체를 다른 개체와 여러 번 비교하면 그 결과는 항상 동일합니다.
    연속적인 x.Equals(y) 호출은 x 및 y에서 참조하는 객체가 수정되지 않는 한 동일한 값을 반환합니다.

  • null로 비교 : 없음 개체가 같은지 null .
    x.Equals(null)false 반환합니다.

GetHashCode 구현 :

  • Equals 와 호환 : 두 객체가 같으면 ( Equals 가 true를 반환한다는 의미), GetHashCode 각각에 대해 동일한 값을 반환 해야 합니다.

  • 넓은 범위 : 두 객체가 같지 않은 경우 ( Equals 은 거짓이라고 함) 해시 코드가 고유 할 확률 이 높아야합니다. 선택할 수있는 값의 수가 제한되어 있으므로 완벽한 해싱이 불가능할 수 있습니다.

  • 염가 : 모든 경우에 해시 코드를 계산하는 것은 저렴해야합니다.

참조 : 오버로드에 대한 지침 Equals () 및 연산자 ==

기본 같음 동작입니다.

EqualsObject 클래스 자체에서 선언됩니다.

public virtual bool Equals(Object obj);

기본적으로 Equals 에는 다음과 같은 동작이 있습니다.

  • 인스턴스가 참조 유형 인 경우 참조가 동일한 경우에만 Equals 이 반환됩니다.

  • 인스턴스가 값 유형이면 Equals 는 유형 및 값이 같은 경우에만 true를 리턴합니다.

  • string 은 특별한 경우입니다. 값 유형처럼 작동합니다.

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            //areFooClassEqual: False
            Foo fooClass1 = new Foo("42");
            Foo fooClass2 = new Foo("42");
            bool areFooClassEqual = fooClass1.Equals(fooClass2);
            Console.WriteLine("fooClass1 and fooClass2 are equal: {0}", areFooClassEqual);
            //False

            //areFooIntEqual: True
            int fooInt1 = 42;
            int fooInt2 = 42;
            bool areFooIntEqual = fooInt1.Equals(fooInt2);
            Console.WriteLine("fooInt1 and fooInt2 are equal: {0}", areFooIntEqual);

            //areFooStringEqual: True
            string fooString1 = "42";
            string fooString2 = "42";
            bool areFooStringEqual = fooString1.Equals(fooString2);
            Console.WriteLine("fooString1 and fooString2 are equal: {0}", areFooStringEqual);
        }
    }

    public class Foo
    {
        public string Bar { get; }

        public Foo(string bar)
        {
            Bar = bar;
        }
    }
}

좋은 GetHashCode 오버라이드 작성하기

GetHashCode 는 Dictionary <> 및 HashTable에서 주요 성능 효과를냅니다.

좋은 GetHashCode 메서드

  • 균등 분포를 가져야한다.
    • 모든 정수는 무작위 인스턴스로 돌아갈 확률이 대략 같아야합니다.
    • 메서드가 각 인스턴스에 대해 동일한 정수 (예 : 상수 '999')를 반환하면 성능이 떨어집니다
  • 빨리해야한다.
    • 이들은 속도 저하가 특징 인 암호화 해시가 아닙니다.
    • 해쉬 함수의 속도가 느릴수록 사전의 속도가 느려집니다.
  • Equals 이 true로 평가되는 두 인스턴스에서 동일한 HashCode를 반환해야합니다.
    • 그렇지 않은 경우 (예 : GetHashCode 가 임의의 숫자를 반환하기 때문에) List , Dictionary 또는 유사 항목에서 항목을 찾을 수 없습니다.

GetHashCode 를 구현하는 좋은 방법은 하나의 소수를 시작 값으로 사용하고 다른 소수를 곱한 유형의 필드의 해시 코드를 그 값에 더하는 것입니다.

public override int GetHashCode()
{
    unchecked // Overflow is fine, just wrap
    {
        int hash = 3049; // Start value (prime number).

        // Suitable nullity checks etc, of course :)
        hash = hash * 5039 + field1.GetHashCode();
        hash = hash * 883 + field2.GetHashCode();
        hash = hash * 9719 + field3.GetHashCode();
        return hash;
    }
}

Equals 메서드에서 사용되는 필드 만 해시 함수에 사용해야합니다.

Dictionary / HashTables에 대해 다른 유형으로 동일한 유형을 처리해야하는 경우 IEqualityComparer를 사용할 수 있습니다.

사용자 지정 형식에서 Equals 및 GetHashCode 재정의

Person 클래스의 경우 :

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Clothes { get; set; }
}

var person1 = new Person { Name = "Jon", Age = 20, Clothes = "some clothes" };
var person2 = new Person { Name = "Jon", Age = 20, Clothes = "some other clothes" };

bool result = person1.Equals(person2); //false because it's reference Equals

그러나 다음과 같이 EqualsGetHashCode 를 정의합니다.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Clothes { get; set; }

    public override bool Equals(object obj)
    {
        var person = obj as Person;
        if(person == null) return false;
        return Name == person.Name && Age == person.Age; //the clothes are not important when comparing two persons
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode()*Age;
    }
}

var person1 = new Person { Name = "Jon", Age = 20, Clothes = "some clothes" };
var person2 = new Person { Name = "Jon", Age = 20, Clothes = "some other clothes" };

bool result = person1.Equals(person2); // result is true

또한 LINQ를 사용하여 사람에 대해 서로 다른 쿼리를 작성하면 EqualsGetHashCode 모두 확인합니다.

var persons = new List<Person>
{
     new Person{ Name = "Jon", Age = 20, Clothes = "some clothes"},
     new Person{ Name = "Dave", Age = 20, Clothes = "some other clothes"},
     new Person{ Name = "Jon", Age = 20, Clothes = ""}
};

var distinctPersons = persons.Distinct().ToList();//distinctPersons has Count = 2

IEqualityComparator의 Equals 및 GetHashCode

주어진 유형 Person :

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Clothes { get; set; }
}

List<Person> persons = new List<Person>
{
    new Person{ Name = "Jon", Age = 20, Clothes = "some clothes"},
    new Person{ Name = "Dave", Age = 20, Clothes = "some other clothes"},
    new Person{ Name = "Jon", Age = 20, Clothes = ""}
};

var distinctPersons = persons.Distinct().ToList();// distinctPersons has Count = 3

하지만 EqualsGetHashCodeIEqualityComparator 로 정의하면 :

public class PersonComparator : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.Name == y.Name && x.Age == y.Age; //the clothes are not important when comparing two persons;
    }

    public int GetHashCode(Person obj) { return obj.Name.GetHashCode() * obj.Age; }
}

var distinctPersons = persons.Distinct(new PersonComparator()).ToList();// distinctPersons has Count = 2

이 쿼리의 경우 Equals true를 반환하고 GetHashCode 가 두 사람에 대해 동일한 해시 코드를 반환하면 두 개체가 동등한 것으로 간주됩니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow