Tip
이 문서는 이미 하나 이상의 프로그래밍 언어를 알고 있으며 C#을 학습하는 개발자를 위한 기본 사항 섹션의 일부입니다. 프로그래밍을 처음 접하는 경우 먼저 시작 자습서로 시작 하세요.
다른 언어에서 오시겠습니까? Java에서 객체에 대한 == 및 JavaScript에서 객체에 대한 === 는 내용이 아니라 동일성을 검사합니다. C# 클래스는 기본적으로 동일한 방식으로 작동합니다. Python에서는 ==가 를 호출하며, C# __eq__가 비교되는 방식과 유사하게 기본적으로 내용을 기준으로 테스트합니다. 또한 C# 구조체는 호출 Equals할 때 값별로 비교됩니다.
C#은 두 종류의 같음을 구분합니다. 값 같음 은 데이터가 일치할 때 두 인스턴스가 같음을 의미합니다. 참조 동일성은 두 변수가 메모리에서 동일한 객체를 가리킬 때만 동일하다는 의미입니다. 이 조건을 ID라고도 합니다. 값 형식은 일반적으로 데이터를 비교하고 참조 형식은 일반적으로 ID를 비교합니다. 형식 작성자는 이러한 기본값을 변경할 수 있지만, 정신 모델은 동일하게 보이는 두 개체가 같지 않거나 한 변수를 통한 돌연변이가 다른 변수가 보는 것을 자동으로 변경하는 미묘한 버그를 방지합니다.
값 형식, 참조 형식 및 기본 동등성
C#의 모든 형식은 값 형식 또는 참조 형식입니다. 값 형식은 변수에 해당 데이터를 직접 보유합니다. 참조 형식은 개체에 대한 참조를 보유합니다. 참조 형식 변수를 다른 변수에 할당하면 두 변수 모두 동일한 개체를 참조합니다. 값 형식 및 참조 형식에 대한 자세한 내용은 형식 시스템 개요를 참조하세요.
기본 같음 동작은 일반적으로 형식의 종류를 따릅니다.
-
기본 제공 숫자 형식 및 열거형은 값 형식입니다. 두
int변수는 숫자 값이 일치할 때 동일합니다. -
구조체는 값 형식입니다. 일반적인
struct는 Equals를 호출할 때 값 동등성을 사용합니다. - 튜플은 값 형식입니다. 두 튜플은 모든 요소 값이 일치할 때 동일합니다.
-
클래스는 참조 형식입니다. 일반 클래스는 참조 같음을 사용하므로
==Equals 두 변수가 동일한 개체를 가리키는지 테스트합니다.
클래스는 참조 동일성을 사용합니다. 데이터가 같은 두 개의 개별 개체는 같지 않지만 동일한 개체를 참조하는 두 개의 변수는 같습니다.
var order1 = new Order(42, "Shoes");
var order2 = new Order(42, "Shoes");
Console.WriteLine(order1 == order2); // => False
Console.WriteLine(order1.Equals(order2)); // => False
Console.WriteLine(ReferenceEquals(order1, order2)); // => False
Order order3 = order1;
Console.WriteLine(order1 == order3); // => True
A는 struct 을 통해 Equals값 같음을 표시합니다. 두 구조체 인스턴스는 필드가 일치할 때 동일합니다.
var pt1 = new Point(3, 4);
var pt2 = new Point(3, 4);
Console.WriteLine(pt1.Equals(pt2)); // => True
일반 구조체는 미리 정의된 == 연산자를 얻지 못합니다. 일반 구조체에 p1 == p2를 작성하는 것은 해당 구조체가 자체 operator ==를 선언하는 경우에만 컴파일됩니다. 구조체에 대한 비교 연산자가 필요한 경우 ==와 !=를 한 쌍으로 정의하고 Equals 및 GetHashCode와 일관되게 유지하세요.
튜플도 값 형식입니다. 모든 요소 값이 일치하면 두 개의 튜플이 동일합니다. 명명된 튜플의 요소 이름은 컴파일 시간 편의성이며 비교하는 동안 고려되지 않습니다. 위치와 값만 중요합니다.
var t1 = (Name: "Grace", Role: "Engineer");
var t2 = (Name: "Grace", Role: "Engineer");
Console.WriteLine(t1 == t2); // => True
튜플 구문 및 분해에 대한 자세한 내용은 튜플 및 분해를 참조하세요.
ID를 직접 테스트하는 데 사용 Object.ReferenceEquals
ReferenceEquals는 형식이 Equals를 재정의하거나 ==를 오버로드하는 방식과 관계없이 항상 동일성을 테스트합니다. 두 변수가 정확히 동일한 개체를 가리키는지 확인해야 하는 경우 ID 진단으로 사용합니다.
var doc1 = new Document("Report");
var doc2 = new Document("Report");
var doc3 = doc1;
Console.WriteLine(ReferenceEquals(doc1, doc2)); // => False
Console.WriteLine(ReferenceEquals(doc1, doc3)); // => True
일반적으로는 Equals 재정의에서 전체 비교를 생략하는 용도로 사용됩니다. 두 인수가 동일한 참조이면 개별 필드를 확인하지 않아도 항상 같은 것으로 간주됩니다.
메모
변수를 인터페이스로 입력하는 경우 인터페이스== 변수가 동일한 개체를 참조하는지 여부를 확인합니다.
Equals에 대한 호출은 여전히 기본 개체의 구현을 실행합니다.
메모
ReferenceEquals 두 인수에 동일한 값이 포함되어 있더라도 값 형식을 비교할 때 항상 반환 false 됩니다. 이 동작은 각 값 형식 인수가 ReferenceEquals에 전달될 때 각각 별도의 힙 객체로 박싱되기 때문에 발생합니다.
형식은 서로 다른 같음 의미 체계를 정의할 수 있습니다.
형식은 기본 동작과 다른 같음 의미 체계를 정의할 수 있습니다 . 가장 일반적인 이유는 값 같음을 구현하기 위해서입니다. 은행 계좌, 인벤토리의 제품 또는 시스템의 사용자와 같은 데이터를 나타내는 형식을 만드는 경우 동일한 값을 가진 인스턴스를 고려합니다. 값 같음을 구현하기 위한 레코드 형식 을 선택하면 컴파일러가 필요한 모든 같음 멤버를 생성합니다.
메모
문자열은 클래스이지만 ==Equals ID가 아닌 문자열 콘텐츠를 비교합니다.
-
==: 같음 연산자입니다. 대부분의 형식은 이 연산자를 기본 같음 검사로 사용합니다. 해당 동작은 형식에 기본 제공 연산자 또는 사용자 정의==연산자가 있는지 여부에 따라 달라집니다. -
!=: 같지 않음 연산자입니다. 형식이 사용자 정의==연산자를 정의하는 경우!=도 정의해야 합니다. - Equals: 모든 형식에서 상속되는 가상 메서드입니다. 형식에 대한 같음 의미 체계를 변경하도록 재정의할 수 있습니다.
- GetHashCode: 해시 기반 컬렉션에서 사용하는 가상 메서드입니다. 두 값이 같으면 해시 코드도 같아야 합니다.
- ReferenceEquals: 항상 ID를 테스트하는 정적 메서드입니다.
값 같음을 위해 레코드 사용
형식이 레코드일 수 있는 경우 데이터 중심 형식 값 동등성을 제공하려면 record 한정자를 사용합니다. 컴파일러는 선언된 모든 속성 값을 비교하는 멤버를 생성EqualsGetHashCode합니다==/!=.
A record class 는 여전히 참조 형식이지만 ID 대신 값을 비교합니다.
var person1 = new Person("Ada", "Lovelace");
var person2 = new Person("Ada", "Lovelace");
Console.WriteLine(person1 == person2); // => True
Console.WriteLine(person1.Equals(person2)); // => True
Console.WriteLine(ReferenceEquals(person1, person2)); // => False
ReferenceEquals는 person1와 person2가 메모리상에서 서로 다른 객체임을 확인하는 반면, ==와 Equals는 컴파일러가 생성한 동등성 비교가 속성 값을 비교하므로 True를 반환합니다.
동일한 컴파일러 생성 방식이 record struct 형식에도 적용됩니다:
var dim1 = new Dimension(1920, 1080);
var dim2 = new Dimension(1920, 1080);
Console.WriteLine(dim1 == dim2); // => True
Console.WriteLine(dim1.Equals(dim2)); // => True
레코드 형식은 자체 형식에 대한 전체 같음 집합을 생성합니다.
record class 및 record struct 형식은 모두 Equals 및 GetHashCode를 재정의합니다. 또한 == 및 != 연산자와 레코드 형식에 대한 형식이 지정된 Equals 메서드도 생성합니다. 따라서 일반 struct와 달리 record struct는 == 및 !=를 자동으로 지원합니다. 레코드 형식 및 해당 같음 의미 체계에 대한 자세한 내용은 레코드를 참조하세요.
참조 형식 멤버가 있는 레코드
레코드의 동등성은 멤버 자체의 동등성 의미 체계를 사용합니다. 각 속성 또는 필드는 자체 Equals 메서드를 사용하여 비교됩니다. 대부분의 스칼라 값(예: int, string또는 DateTime)의 경우 이 방법은 레코드 멤버의 값을 비교합니다. 이러한 형식은 참조별로 비교되는 일반적인 변경 가능한 컬렉션 List<T>T[]에서 미묘하게 발생하므로 동일한 콘텐츠를 가진 서로 다른 목록 개체 를 포함하는 두 레코드 인스턴스는 합성된 레코드 같음으로 간주되지 않습니다 .
var playlist1 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
var playlist2 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
Console.WriteLine(playlist1.Equals(playlist2)); // => False (different List instances)
Console.WriteLine(playlist1.Tracks.SequenceEqual(playlist2.Tracks)); // => True
playlist1 은 playlist2 별도의 List<string> 인스턴스입니다. 내용이 일치하더라도 Equals은(는) false을(를) 반환합니다.
레코드 동등성이 컬렉션 내용을 반영해야 하는 경우 몇 가지 선택지가 있습니다:
-
레코드에
IEquatable<T>를 구현하고 컬렉션 멤버에Equals를 사용하도록 Enumerable.SequenceEqual를 재정의합니다. -
값이 같은 컬렉션 형식을 사용합니다 (예: 사용자 지정
IEqualityComparer<T>또는 고유한Equals요소가 비교되는 형식). - ID를 중심으로 디자인: 레코드가 순수 값이 아닌 엔터티를 나타내는 경우 컬렉션 멤버에 대한 참조 같음이 의도적인 것일 수 있습니다.
Important
오늘날 C#에서 동등성을 직접 구현하는 경우는 드뭅니다. 레코드는 값 같음의 일반적인 시나리오를 자동으로 처리합니다. 예를 들어 형식이 레코드가 아닌 기본 클래스에서 파생되어야 하기 때문에 같음을 수동으로 구현해야 하는 경우 언어 참조에서 형식이 레코드가 될 수 없는 경우 직접 같음 구현 을 참조하세요.
참고하십시오
- 형식 시스템 개요
- 클래스
- 구조체
- 레코드
- 튜플 및 구조 분해.
- 같음 연산자(언어 참조).
- 클래스 계층 구조의 동등성 — 다형적 동등성에 대한 고급 지침.
- 산술, 비교, 논리 및 대입 연산 자 - 산술, 논리 및 대입 연산자와 함께 같음 연산자 설문 조사입니다.
.NET