C# Language
같음 및 GetHashCode
수색…
비고
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
는 Object
클래스 자체에서 선언됩니다.
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
그러나 다음과 같이 Equals
와 GetHashCode
를 정의합니다.
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를 사용하여 사람에 대해 서로 다른 쿼리를 작성하면 Equals
와 GetHashCode
모두 확인합니다.
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
하지만 Equals
와 GetHashCode
를 IEqualityComparator
로 정의하면 :
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
가 두 사람에 대해 동일한 해시 코드를 반환하면 두 개체가 동등한 것으로 간주됩니다.