다음 표현이 다른 이유는 무엇입니까?
[1] (object)0 == (object)0 //false
[2] ((object)0).Equals((object)0) // true
실제로 .NET 런타임이 box
정수를 사용하고 참조 비교를 시작 하기 때문에 [1]을 완전히 이해할 수 있습니다 . 그러나 [2]가 다른 이유는 무엇입니까?
답변
호출이 다르게 작동하는 이유는 매우 다른 메서드에 바인딩되기 때문입니다.
==
경우 정적 기준 항등 연산자로 결합한다. 2 개의 독립적 인 박스형 int
값이 생성되었으므로 동일한 참조가 아닙니다.
두 번째 경우에는 인스턴스 메서드에 바인딩합니다 Object.Equals
. 이것은 필터링되는 가상 방법 Int32.Equals
이며 이것은 박스형 정수를 확인합니다. 두 정수 값은 모두 0이므로 동일합니다.
답변
int 값 0
(또는 다른 값 유형)을로 캐스팅 object
하면 값이 boxed 됩니다. 각 캐스트 object
는 다른 상자 (즉, 다른 개체 인스턴스) 를 생성합니다. ==
위한 오퍼레이터 object
입력을 수행하는 기준 비교하여, 왼쪽 및 오른쪽은 동일한 인스턴스 아니므 false를 반환하므로.
반면에 Equals
가상 메소드 인를 사용하면 실제 boxed 유형의 구현을 사용합니다. 즉 Int32.Equals
, 두 객체가 동일한 값을 갖기 때문에 true를 반환합니다.
답변
==
작업자는 고정되고, 가상이 아니다. 정확한 코드를 실행합니다.object
클래스가 정의 (`객체는 피연산자의 컴파일 시간 유형 임)를 실행하여 두 객체의 런타임 유형에 관계없이 참조 비교를 수행합니다.
Equals
방법은 가상 인스턴스 메소드이다. object
클래스 의 코드가 아닌 (첫 번째) 개체의 실제 런타임 유형에 정의 된 코드를 실행합니다 . 이 경우 객체는 int
이므로 int
유형이 Equals
메서드에 대해 정의 하는 값 비교를 수행합니다 .
답변
Equals()
방법은 가상입니다.
따라서 callsite가 캐스트되는 경우에도 항상 구체적인 구현을 호출합니다 object
.
값으로 비교하도록 int
재정의 Equals()
하므로 값 비교를 얻을 수 있습니다.
답변
==
사용하다: Object.ReferenceEquals
Object.Equals
값을 비교합니다.
그만큼 object.ReferenceEquals
메서드는 참조를 비교합니다. 개체를 할당 할 때 메모리 힙에있는 개체의 데이터 외에 메모리 위치를 나타내는 값이 포함 된 참조를받습니다.
이 object.Equals
메서드는 개체의 내용을 비교합니다. 먼저 object.ReferenceEquals와 마찬가지로 참조가 동일한 지 확인합니다. 그러나 그런 다음 파생 된 Equals 메서드를 호출하여 동등성을 추가로 테스트합니다. 이것 좀 봐:
System.Object a = new System.Object();
System.Object b = a;
System.Object.ReferenceEquals(a, b); //returns true
답변
C # 연산자는 토큰 ==
을 사용하여 두 개의 다른 연산자, 즉 정적으로 오버로드 가능한 비교 연산자와 오버로드 불가능한 참조 비교 연산자를 나타냅니다. ==
토큰을 발견하면 먼저 피연산자 유형에 적용 할 수있는 동등성 테스트 오버로드가 있는지 확인합니다. 그렇다면 해당 오버로드를 호출합니다. 그렇지 않으면 유형이 참조 비교 연산자에 적용 가능한지 여부를 확인합니다. 그렇다면 해당 연산자를 사용합니다. 피연산자 유형에 적용 할 수있는 연산자가 없으면 컴파일이 실패합니다.
이 코드 (Object)0
는 모든 값 유형과 마찬가지로 Int32
to Object
:를 업 캐스트하지 않습니다 . Int32
실제로 두 유형을 나타냅니다.이 유형 중 하나는 값과 저장 위치 (예 : 리터럴 0)를 설명하지만 아무것도 파생되지 않으며 그 중 하나는 설명합니다. 힙 개체 및 파생 Object
: 후자의 유형 만으로 업 캐스트 될 수 있으므로 Object
컴파일러는 후자의 유형의 새 힙 객체를 만들어야합니다. 를 호출 할 때마다 (Object)0
새 힙 개체 가 만들어 지므로 두 피연산자 ==
는 서로 다른 개체이며 각각 독립적으로 Int32
값 0을 캡슐화합니다 .
클래스 Object
에는 같음 연산자에 대해 정의 된 사용 가능한 오버로드가 없습니다. 결과적으로 컴파일러는 오버로드 된 같음 테스트 연산자를 사용할 수 없으며 참조 같음 테스트 사용으로 돌아갑니다. 두 피연산자가 ==
별개의 개체 를 참조하기 때문에 false
. 두 번째 비교는 하나의 힙 오브젝트 인스턴스가 Int32
다른 것과 동일한 지 묻기 때문에 성공합니다 . 해당 인스턴스는 다른 개별 인스턴스와 동일하다는 것이 무엇을 의미하는지 알고 있기 때문에 true
.
답변
두 수표가 모두 다릅니다. 위한 첫 번째 수표 의 신원 에 대한 두번째 같음 . 일반적으로 동일한 객체를 참조하는 경우 두 용어는 동일합니다. 이것은 그들이 동등하다는 것을 의미합니다. 값이 같으면 두 항은 같습니다.
프로그래밍의 관점에서 정체성은 일반적으로 참조 평등에 의해 엉망입니다. 두 용어에 대한 포인터가 같으면 (!), 그들이 가리키는 개체는 정확히 같은 것입니다. 그러나 포인터가 다른 경우 포인터가 가리키는 개체의 값은 여전히 동일 할 수 있습니다. C #에서는 정적 Object.ReferenceEquals
멤버를 사용하여 ID를 확인할 수 있으며 비 정적 Object.Equals
멤버를 사용하여 동등성을 확인할 수 있습니다 . 두 개의 정수를 객체에 캐스팅하므로 ( “boxing”, btw라고 함)의 피연산자 는 기본적으로 매핑되고 ID 를 확인하는 첫 번째 검사 ==
를 object
수행합니다 Object.ReferenceEquals
. 비 정적 Equals
멤버 를 명시 적으로 호출하는 경우 동적 디스패치 는를 호출하여 Int32.Equals
동등성을 확인합니다.
두 개념은 비슷하지만 같지는 않습니다. 처음에는 혼란스러워 보일 수 있지만 작은 차이가 매우 중요합니다! “앨리스”와 “밥”이라는 두 사람을 상상해보십시오. 둘 다 노란 집에 살고 있습니다. 앨리스와 밥이 주택 색깔 만 다른 지역에 살고 있다는 가정에 따르면 둘 다 다른 노란색 주택에 살 수 있습니다. 두 집을 비교하면 두 집이 모두 노란색이기 때문에 절대적으로 동일하다는 것을 알 수 있습니다! 그러나 그들은 같은 집을 공유하지 않기 때문에 그들의 집은 동일 하지만 동일 하지는 않습니다 . 정체성은 그들이 같은 집에 살고 있음을 의미합니다 .
참고 : 일부 언어는 ===
ID를 확인하기 위해 연산자를 정의합니다 .