C # .Equals (), .ReferenceEquals () 및 == 연산자
이 세 가지에 대한 나의 이해는 다음과 같습니다.
.Equals()
데이터 동등성 테스트 (더 나은 설명이없는 경우).Equals()
동일한 객체의 다른 인스턴스에 대해 True를 반환 할 수 있으며 이것은 가장 일반적으로 재정의되는 메서드입니다..ReferenceEquals()
두 개체가 동일한 인스턴스이고 재정의 할 수 없는지 여부를 테스트합니다.==
ReferenceEquals()
기본적으로 와 동일 하지만 이것은 무시할 수 있습니다.
그러나 C # 스테이션 은 다음과 같이 말합니다.
개체 클래스에서
Equals
및ReferenceEquals
메서드는ReferenceEquals
개체 인스턴스에서만 작동 한다는 점을 제외하면 의미 상 동일 합니다.ReferenceEquals
방법은 정적이다.
이제 이해가 안 돼요. 누구든지 이것에 대해 밝힐 수 있습니까?
혼란의 원인은 "... Equals 가 개체 인스턴스에서만 작동 한다는 점을 제외하면 C # 스테이션에서 추출한 내용에 오타가있는 것 같습니다 . ReferenceEquals 메서드는 정적입니다."
각각의 의미 론적 의미의 차이에 대해 느슨하게 맞습니다 ( "동일한 객체의 다른 인스턴스"가 약간 혼란스러워 보이지만 "동일 유형 의 다른 인스턴스"로 읽어야 함 ).
우리가 그것을 제쳐두면, 당신의 질문의 마지막 부분, 즉 그것들이 일반 System.Object
인스턴스와 System.Object
참조로 어떻게 작동 하는지를 다루도록합시다 (우리는 둘 다의 비-다형성을 피하기 위해 필요합니다 ==
). 여기서 세 가지 작업은 모두 동일 하게 작동 하지만주의 사항 :에서 Equals
호출 할 수 없습니다 null
.
Equals
하나의 매개 변수 (일 수 있음 null
)를 사용 하는 인스턴스 메소드입니다 . 인스턴스 메서드 (실제 객체에서 호출되어야 함)이므로 null
-reference에서 호출 할 수 없습니다 .
ReferenceEquals
두 개의 매개 변수 를 취하는 정적 메소드입니다 null
. 둘 중 하나는 . 정적이기 때문에 (object instance 와 연결되지 않음 ) NullReferenceException
어떤 상황에서도를 던지지 않습니다 .
==
는 연산자이며,이 경우 ( object
)는와 동일하게 작동합니다 ReferenceEquals
. NullReferenceException
어느 쪽도 던지지 않습니다 .
설명하기 위해 :
object o1 = null;
object o2 = new object();
//Technically, these should read object.ReferenceEquals for clarity, but this is redundant.
ReferenceEquals(o1, o1); //true
ReferenceEquals(o1, o2); //false
ReferenceEquals(o2, o1); //false
ReferenceEquals(o2, o2); //true
o1.Equals(o1); //NullReferenceException
o1.Equals(o2); //NullReferenceException
o2.Equals(o1); //false
o2.Equals(o2); //true
주제에 대한 이 MSDN 문서 를 살펴보십시오 .
관련 포인트는 다음과 같습니다.
참조 동등성을 확인하려면 ReferenceEquals를 사용하십시오. 값이 같은지 확인하려면 Equals 또는 Equals를 사용하십시오.
기본적으로 == 연산자는 두 참조가 동일한 객체를 나타내는 지 확인하여 참조 동등성을 테스트하므로 참조 유형은이 기능을 얻기 위해 == 연산자를 구현할 필요가 없습니다. 유형이 변경 불가능한 경우 (즉, 인스턴스에 포함 된 데이터를 변경할 수 없음), 참조 같음 대신 값 같음을 비교하기 위해 연산자 ==를 오버로딩하는 것이 유용 할 수 있습니다. 같은 가치.
도움이 되었기를 바랍니다!
.ReferenceEquals에 대한 이해가 정확합니다.
.Equals는 값 유형에 대한 데이터 동등성을 확인하고 값이 아닌 유형 (일반 개체)에 대한 참조 동등성을 확인합니다.
객체가 어떤 형태의 데이터 동등성 검사를 수행하도록 Equals를 재정의 할 수 있습니다.
편집 : 또한 .ReferenceEquals는 값 유형에 사용할 수 없습니다 (잘 할 수 있지만 항상 거짓입니다)
"null"과 비교하는 것에 대해 5 센트를 추가하고 싶습니다.
ReferenceEquals (객체, 객체)는 "(객체) arg1 == arg2"와 동일합니다 (따라서 값 유형의 경우 boxing이 발생하고 시간이 걸립니다). 그러나이 방법은 다음과 같은 여러 상황에서 null 인수를 확인하는 유일한 100 % 안전한 방법입니다.
- a)를 통해 회원에게 전화하기 전에. 운영자
- b) AS 연산자의 결과 확인.
== 및 Equals (). ReferenceEquals가 null 검사를 통해 100 % 안전하다고 말하는 이유는 무엇입니까? 핵심 교차 프로젝트 라이브러리에 일반 확장을 작성하고 일반 매개 변수 유형을 일부 도메인 유형으로 제한한다고 가정 해보십시오. 이 유형은 "=="연산자를 도입 할 수 있습니다-지금 또는 나중에 (그리고 저를 믿습니다. 저는이 연산자가 매우 "이상한"논리를 가질 수 있습니다. 특히 도메인이나 지속성 객체에 관해서는 그렇습니다). null 인수를 확인한 다음 멤버 작업을 호출하려고합니다. 놀랍게도 여기서 NullRef를 가질 수 있습니다. == 연산자는 Equals ()와 거의 동일하기 때문에 매우 사용자 정의되고 예측할 수 없습니다. 하지만 고려해야 할 차이점이 있습니다. 일반 매개 변수를 일부 사용자 정의 유형으로 제한하지 않으면 (== 유형이 "클래스"인 경우에만 사용할 수 있음) == 연산자는 객체와 동일합니다. . ReferenceEquals (..). Equals 구현은 가상이므로 항상 최종 유형에서 사용됩니다.
따라서 내 권장 사항은 자신의 유형을 작성하거나 잘 알려진 유형에서 파생 될 때 ==를 사용하여 null을 확인할 수 있다는 것입니다. 그렇지 않으면 object.ReferenceEquals (arg, null)를 사용합니다.
Object 클래스에서 .Equals는 동일성이 아닌 ID를 구현합니다. 참조가 동일한 지 확인합니다. 코드는 다음과 같을 수 있습니다.
public virtual Boolean Equals(Object other) {
if (this == other) return true;
return false;
}
클래스에서 .Equals를 구현하는 동안 기본 클래스가 Object가 아닌 경우에만 기본 클래스 .Equals를 호출해야합니다. 네, 복잡합니다.
더욱이 파생 클래스는 .Equals를 재정의 할 수 있으므로이를 호출하여 ID를 확인하기 위해 Microsoft에서 추가 한 정적 .ReferenceEquals 메서드를 사용할 수 없습니다.
어떤 클래스를 사용하면 논리적으로 .Equals는 동등성을 확인하고 .ReferenceEquals는 ID를 확인합니다.
Ani의 훌륭한 답변 을 확장 하여 참조 유형 및 재정의 된 같음 방법을 다룰 때 주요 차이점을 보여줍니다.
- 이 코드의 작동 버전은 https://dotnetfiddle.net/dFKMhB 에서 볼 수 있습니다.
- 또한,이 코드에 붙여 넣을 수 LinqPad 과로 실행
Language: C# Program
.
.
void Main()
{
//odd os are null; evens are not null
object o1 = null;
object o2 = new object();
object o3 = null;
object o4 = new object();
object o5 = o1;
object o6 = o2;
Demo d1 = new Demo(Guid.Empty);
Demo d2 = new Demo(Guid.NewGuid());
Demo d3 = new Demo(Guid.Empty);
Debug.WriteLine("comparing null with null always yields true...");
ShowResult("ReferenceEquals(o1, o1)", () => ReferenceEquals(o1, o1)); //true
ShowResult("ReferenceEquals(o3, o1)", () => ReferenceEquals(o3, o1)); //true
ShowResult("ReferenceEquals(o5, o1)", () => ReferenceEquals(o5, o1)); //true
ShowResult("o1 == o1", () => o1 == o1); //true
ShowResult("o3 == o1", () => o3 == o1); //true
ShowResult("o5 == o1", () => o5 == o1); //true
Debug.WriteLine("...though because the object's null, we can't call methods on the object (i.e. we'd get a null reference exception).");
ShowResult("o1.Equals(o1)", () => o1.Equals(o1)); //NullReferenceException
ShowResult("o1.Equals(o2)", () => o1.Equals(o2)); //NullReferenceException
ShowResult("o3.Equals(o1)", () => o3.Equals(o1)); //NullReferenceException
ShowResult("o3.Equals(o2)", () => o3.Equals(o2)); //NullReferenceException
ShowResult("o5.Equals(o1)", () => o5.Equals(o1)); //NullReferenceException
ShowResult("o5.Equals(o2)", () => o5.Equals(o1)); //NullReferenceException
Debug.WriteLine("Comparing a null object with a non null object always yeilds false");
ShowResult("ReferenceEquals(o1, o2)", () => ReferenceEquals(o1, o2)); //false
ShowResult("ReferenceEquals(o2, o1)", () => ReferenceEquals(o2, o1)); //false
ShowResult("ReferenceEquals(o3, o2)", () => ReferenceEquals(o3, o2)); //false
ShowResult("ReferenceEquals(o4, o1)", () => ReferenceEquals(o4, o1)); //false
ShowResult("ReferenceEquals(o5, o2)", () => ReferenceEquals(o3, o2)); //false
ShowResult("ReferenceEquals(o6, o1)", () => ReferenceEquals(o4, o1)); //false
ShowResult("o1 == o2)", () => o1 == o2); //false
ShowResult("o2 == o1)", () => o2 == o1); //false
ShowResult("o3 == o2)", () => o3 == o2); //false
ShowResult("o4 == o1)", () => o4 == o1); //false
ShowResult("o5 == o2)", () => o3 == o2); //false
ShowResult("o6 == o1)", () => o4 == o1); //false
ShowResult("o2.Equals(o1)", () => o2.Equals(o1)); //false
ShowResult("o4.Equals(o1)", () => o4.Equals(o1)); //false
ShowResult("o6.Equals(o1)", () => o4.Equals(o1)); //false
Debug.WriteLine("(though again, we can't call methods on a null object:");
ShowResult("o1.Equals(o2)", () => o1.Equals(o2)); //NullReferenceException
ShowResult("o1.Equals(o4)", () => o1.Equals(o4)); //NullReferenceException
ShowResult("o1.Equals(o6)", () => o1.Equals(o6)); //NullReferenceException
Debug.WriteLine("Comparing 2 references to the same object always yields true");
ShowResult("ReferenceEquals(o2, o2)", () => ReferenceEquals(o2, o2)); //true
ShowResult("ReferenceEquals(o6, o2)", () => ReferenceEquals(o6, o2)); //true <-- Interesting
ShowResult("o2 == o2", () => o2 == o2); //true
ShowResult("o6 == o2", () => o6 == o2); //true <-- Interesting
ShowResult("o2.Equals(o2)", () => o2.Equals(o2)); //true
ShowResult("o6.Equals(o2)", () => o6.Equals(o2)); //true <-- Interesting
Debug.WriteLine("However, comparing 2 objects may yield false even if those objects have the same values, if those objects reside in different address spaces (i.e. they're references to different objects, even if the values are similar)");
Debug.WriteLine("NB: This is an important difference between Reference Types and Value Types.");
ShowResult("ReferenceEquals(o4, o2)", () => ReferenceEquals(o4, o2)); //false <-- Interesting
ShowResult("o4 == o2", () => o4 == o2); //false <-- Interesting
ShowResult("o4.Equals(o2)", () => o4.Equals(o2)); //false <-- Interesting
Debug.WriteLine("We can override the object's equality operator though, in which case we define what's considered equal");
Debug.WriteLine("e.g. these objects have different ids, so we treat as not equal");
ShowResult("ReferenceEquals(d1,d2)",()=>ReferenceEquals(d1,d2)); //false
ShowResult("ReferenceEquals(d2,d1)",()=>ReferenceEquals(d2,d1)); //false
ShowResult("d1 == d2",()=>d1 == d2); //false
ShowResult("d2 == d1",()=>d2 == d1); //false
ShowResult("d1.Equals(d2)",()=>d1.Equals(d2)); //false
ShowResult("d2.Equals(d1)",()=>d2.Equals(d1)); //false
Debug.WriteLine("...whilst these are different objects with the same id; so we treat as equal when using the overridden Equals method...");
ShowResult("d1.Equals(d3)",()=>d1.Equals(d3)); //true <-- Interesting (sort of; different to what we saw in comparing o2 with o6; but is just running the code we wrote as we'd expect)
ShowResult("d3.Equals(d1)",()=>d3.Equals(d1)); //true <-- Interesting (sort of; different to what we saw in comparing o2 with o6; but is just running the code we wrote as we'd expect)
Debug.WriteLine("...but as different when using the other equality tests.");
ShowResult("ReferenceEquals(d1,d3)",()=>ReferenceEquals(d1,d3)); //false <-- Interesting (sort of; same result we had comparing o2 with o6; but shows that ReferenceEquals does not use the overridden Equals method)
ShowResult("ReferenceEquals(d3,d1)",()=>ReferenceEquals(d3,d1)); //false <-- Interesting (sort of; same result we had comparing o2 with o6; but shows that ReferenceEquals does not use the overridden Equals method)
ShowResult("d1 == d3",()=>d1 == d3); //false <-- Interesting (sort of; same result we had comparing o2 with o6; but shows that ReferenceEquals does not use the overridden Equals method)
ShowResult("d3 == d1",()=>d3 == d1); //false <-- Interesting (sort of; same result we had comparing o2 with o6; but shows that ReferenceEquals does not use the overridden Equals method)
Debug.WriteLine("For completeness, here's an example of overriding the == operator (wihtout overriding the Equals method; though in reality if overriding == you'd probably want to override Equals too).");
Demo2 d2a = new Demo2(Guid.Empty);
Demo2 d2b = new Demo2(Guid.NewGuid());
Demo2 d2c = new Demo2(Guid.Empty);
ShowResult("d2a == d2a", () => d2a == d2a); //true
ShowResult("d2b == d2a", () => d2b == d2a); //false
ShowResult("d2c == d2a", () => d2c == d2a); //true <-- interesting
ShowResult("d2a != d2a", () => d2a != d2a); //false
ShowResult("d2b != d2a", () => d2b != d2a); //true
ShowResult("d2c != d2a", () => d2c != d2a); //false <-- interesting
ShowResult("ReferenceEquals(d2a,d2a)", () => ReferenceEquals(d2a, d2a)); //true
ShowResult("ReferenceEquals(d2b,d2a)", () => ReferenceEquals(d2b, d2a)); //false
ShowResult("ReferenceEquals(d2c,d2a)", () => ReferenceEquals(d2c, d2a)); //false <-- interesting
ShowResult("d2a.Equals(d2a)", () => d2a.Equals(d2a)); //true
ShowResult("d2b.Equals(d2a)", () => d2b.Equals(d2a)); //false
ShowResult("d2c.Equals(d2a)", () => d2c.Equals(d2a)); //false <-- interesting
}
//this code's just used to help show the output in a friendly manner
public delegate bool Statement();
void ShowResult(string statementText, Statement statement)
{
try
{
Debug.WriteLine("\t{0} => {1}",statementText, statement());
}
catch(Exception e)
{
Debug.WriteLine("\t{0} => throws {1}",statementText, e.GetType());
}
}
class Demo
{
Guid id;
public Demo(Guid id) { this.id = id; }
public override bool Equals(object obj)
{
return Equals(obj as Demo); //if objects are of non-comparable types, obj will be converted to null
}
public bool Equals(Demo obj)
{
if (obj == null)
{
return false;
}
else
{
return id.Equals(obj.id);
}
}
//if two objects are Equal their hashcodes must be equal
//however, if two objects hash codes are equal it is not necessarily true that the objects are equal
//i.e. equal objects are a subset of equal hashcodes
//more info here: https://stackoverflow.com/a/371348/361842
public override int GetHashCode()
{
return id.GetHashCode();
}
}
class Demo2
{
Guid id;
public Demo2(Guid id)
{
this.id = id;
}
public static bool operator ==(Demo2 obj1, Demo2 obj2)
{
if (ReferenceEquals(null, obj1))
{
return ReferenceEquals(null, obj2); //true if both are null; false if only obj1 is null
}
else
{
if(ReferenceEquals(null, obj2))
{
return false; //obj1 is not null, obj2 is; therefore false
}
else
{
return obj1.id == obj2.id; //return true if IDs are the same; else return false
}
}
}
// NB: We also HAVE to override this as below if overriding the == operator; this is enforced by the compiler. However, oddly we could choose to override it different to the below; but typically that would be a bad idea...
public static bool operator !=(Demo2 obj1, Demo2 obj2)
{
return !(obj1 == obj2);
}
}
Equals()
기본 유형 (값 / 참조)에 따라 해시 코드 또는 동등성 ReferenceEquals()
을 확인하며 항상 해시 코드를 확인합니다. 두 개체가 동일한 메모리 위치를 가리키는 경우 ReferenceEquals
반환 true
합니다.
double e = 1.5;
double d = e;
object o1 = d;
object o2 = d;
Console.WriteLine(o1.Equals(o2)); // True
Console.WriteLine(Object.Equals(o1, o2)); // True
Console.WriteLine(Object.ReferenceEquals(o1, o2)); // False
Console.WriteLine(e.Equals(d)); // True
Console.WriteLine(Object.Equals(e, d)); // True
Console.WriteLine(Object.ReferenceEquals(e, d)); // False
참고 URL : https://stackoverflow.com/questions/3869601/c-sharp-equals-referenceequals-and-operator
'programing tip' 카테고리의 다른 글
정규식의 문자 클래스 (대괄호)에서 점을 이스케이프해야합니까? (0) | 2020.10.22 |
---|---|
새 날짜 ( "2017-01-01")와 새 날짜 ( "2017-1-1")의 차이점은 무엇입니까? (0) | 2020.10.22 |
index.html 변경 후 GitHub 페이지에 변경 사항이 표시되는 데 걸리는 시간 (0) | 2020.10.22 |
R : 슬롯이란 무엇입니까? (0) | 2020.10.22 |
copyWithZone 구현시 모범 사례 : (0) | 2020.10.22 |