많은 C# 교과서에서는 객체 평등의 개념을 강조합니다. 우리 모두는 C#의 세계에는 두 가지 종류의 동등성이 있다는 것을 알고 있습니다. 하나는 논리적 동등성입니다. 두 개체가 논리적으로 동일한 값을 나타내는 경우 논리적 동등성이 있다고 합니다. 다른 하나는 참조 동일성입니다. 두 참조가 동일한 객체 인스턴스를 가리키는 경우 참조 동일성이 있다고 합니다.
우리 모두 알고 있듯이 Object 유형에는 두 객체가 동일한지 확인하는 데 사용할 수 있는 Equals라는 인스턴스 메서드가 있습니다. Object's Equals의 기본 구현은 참조 동일성을 위해 두 객체를 비교합니다. 개체 파생 클래스 ValueTpye는 두 개체의 논리적 동등성을 비교하는 Equals 메서드를 재정의합니다. 즉, C#에서 참조 유형에 대한 Equals의 기본 버전은 참조 동일성에 초점을 맞추고 값 유형은 논리적 동일성에 중점을 둡니다. 물론 이것이 항상 우리를 만족시키는 것은 아닙니다. 따라서 참조 형식의 논리적 동등성에 더 관심이 있을 때마다 Equals 메서드를 재정의해야 합니다.
기본 비교 방법을 변경하기 위해 참조 유형의 Equals 메서드를 재정의하는 유명한 예는 String 클래스입니다. string1.Equals(string2)와 같은 코드를 작성할 때 두 참조 string1과 string2가 동일한 인스턴스를 가리키는지(참조 동일성) 비교하는 것이 아니라, string1과 string2에 포함된 문자가 동일한지(논리적) 비교합니다. 평등).
오해 1: Equals 메소드와 == 연산자의 기본 동작은 동일합니다.
참조 유형의 경우 == 연산자가 오버로드되지 않고 상위 유형이 Equals 메서드를 재정의하지 않는 경우 참조 유형의 Equals 메서드와 == 연산자는 동일한 기본 동작을 갖습니다. , they 비교되는 것은 객체의 참조 동일성입니다. 그러나 값 유형의 경우에는 전혀 그렇지 않습니다! 사용자 정의 값 유형에 대해 연산자==를 오버로드하지 않으면 myStruct1 == myStruct2와 같은 코드를 작성할 수 없습니다. 그렇지 않으면 값 유형에 같음 연산자 오버로드의 기본 구현이 없기 때문에 컴파일 오류가 발생합니다.
오해 2: 사용자 정의 클래스에서 Equals 메서드의 기본 구현은 자동으로 Operator== 메서드를 호출하거나, Operator== 메서드의 기본 구현은 자동으로 Equals 메서드를 호출합니다.
사람들이 특정 유형이 참조 유형이므로 Equals 메소드의 기본 구현이 자동으로 Operator== 메소드를 호출한다고 말하는 것을 자주 듣습니다. 이 진술은 완전히 불합리합니다. 위에서 언급했듯이 참조 유형의 Equals 메서드의 기본 구현은 Object에서 나오는 반면, 값 유형의 기본 구현은 TypeValue에서 나옵니다. == 연산자를 사용하더라도 Object 또는 TypeValue의 오버로드된 버전을 사용합니다. 원칙적으로 클래스의 Equals 메서드를 재정의하지 않는 한 해당 클래스는 상위 클래스의 구현을 상속하며 상위 클래스는 하위 유형 연산자 오버로드를 사용할 기회가 없습니다. 마찬가지로 클래스의 == 연산자 오버로드에서 Equals 메서드를 호출하지 않는 한 자동으로 호출되지 않습니다.
오해 3: 값 유형의 기본 Equals 구현은 두 객체를 조금씩 비교합니다.
어떤 사람들은 값 유형에 대한 Equals의 기본 구현이 메모리에 있는 두 개체의 비트 표현을 비교하는 것이라고 생각합니다. 즉, 모든 이진 비트가 동일하면 두 개체가 동일하다는 의미입니다. 이는 정확하지 않습니다. 실수 값 유형에 대한 Equals의 기본 구현은 값 유형의 각 필드에 대해 필드 유형의 Equals 메서드를 호출하는 것이므로 모든 필드의 Equals 메서드가 true를 반환하는 경우에만 동일할 수 있습니다. 예를 들어 보겠습니다.
class MyClass { public override bool Equals(object obj) { Console.WriteLine("MyClass的Equals方法被调用了。"); return true; } } struct MyStruct { public MyClass Filed; } class Program { staticvoid Main(string[] args) { MyStruct a; MyStruct b; a.Filed = new MyClass(); b.Filed = new MyClass(); Console.WriteLine(a.Equals(b)); } }
분명히 a와 b는 완전히 다른 이진 비트 표현을 가지고 있습니다. 그러나 최종 인쇄 결과는 다음과 같습니다.
MyClass의 Equals 메서드가 호출되었습니다.
True
이는 값 유형의 기본 구현이 필드의 Equals 메소드를 호출하는 대신 두 객체가 동일한지 여부를 결정함을 보여줍니다. than by 바이너리 비트가 일치하는지 비교하여 결정됩니다.
오해 4: Equals는 매우 기본적이고 일반적으로 사용되는 방법이므로 기본 구현에는 성능 문제가 없습니다.
참조 유형의 경우 Equals의 기본 구현은 매우 간단합니다. 두 참조가 동일한 유형인지, 두 참조가 동일한 메모리를 가리키는지 여부만 확인하면 됩니다. 따라서 성능에는 문제가 없습니다. 그러나 값 유형의 경우 Equals의 작업은 그렇게 간단하지 않습니다. 두 개체의 모든 필드를 비교해야 합니다. 즉, 필드별로 필드 유형의 Equals를 호출해야 합니다. ValueType(값 유형의 Equals 메소드가 기본적으로 구현됨)에서는 모든 하위 유형에 어떤 필드가 포함되어 있는지 알 수 없으므로 하위 유형 필드의 Equals 메소드를 호출하려면 Equals of ValueType이 필요합니다. 반사 기술을 사용합니다. 이미 알고 있듯이 리플렉션은 성능 친화적인 기술이 아니므로 값 형식의 Equals 메서드는 효율적이지 않습니다. 이것이 바로 Microsoft에서 사용자 지정 값 유형에 대해 Equals 메서드를 재정의할 것을 권장하는 이유입니다.
C# 초보자가 Equals 메서드에 대해 흔히 오해하는 몇 가지 관련 기사를 보려면 다음을 참조하세요. PHP 중국어 웹사이트를 주목하세요!