C #이 두 객체 유형을 서로 비교하지 못하는 이유와 VB는 왜 그렇지 않습니까?


152

C #에 두 개의 개체가 있으며 부울인지 또는 다른 유형인지 알 수 없습니다. 그러나 C #을 비교하려고하면 올바른 대답을하지 못합니다. VB.NET과 동일한 코드를 사용해 보았습니다.

해결책이 있다면 누구 든지이 문제를 해결하는 방법을 말해 줄 수 있습니까?

씨#:

object a = true;
object b = true;
object c = false;
if (a == b) c = true;
MessageBox.Show(c.ToString()); //Outputs False !!

VB.NET :

Dim a As Object = True
Dim b As Object = True
Dim c As Object = False
If (a = b) Then c = True
MessageBox.Show(c.ToString()) '// Outputs True

3
평등 비교자를로 변경하면 a.Equals(b)어떻게됩니까?
Jason Meckley

8
이것은 교육 학적 목적에 좋은 질문입니다.
Lobo

10
VB.NET 코드가 C # 코드와 같지 않기 때문입니다.
Security Hound

9
당신에게 할당 할 때 a권투를하고 포함하는 상자를 만듭니다 true. 당신에게 할당 할 때 당신 은 또한 다른 상자 b를 얻을 . 당신은 비교 할 때 와 모두 컴파일시 타입이기 때문에, 당신은 과부하 전화 는 C # 언어 사양에 의해 정의합니다. 이 오버로드는 참조가 동일한 객체로 이동하는지 확인합니다. 당신이 가지고 있기 때문에 두 개의 상자를, 결과는 , 당신 "에서"문 의지하지 실행합니다. 이것을 더 잘 이해하려면 다음과 같이 할당을 변경하십시오 . 이제 상자가 하나뿐입니다. trueabobjectoperator ==(object, object)falseifbobject b = a;
Jeppe Stig Nielsen 님이

3
"VB.NET과 C #이 다른 억양으로 사용되는 언어와 같다고 가정 할 때주의하십시오"
AakashM

답변:


168

C #에서 ==연산자 (참조 유형 표현식에 적용되는 경우)는 오버로드 되지 않는 한 참조 동등성 검사를 수행합니다 . 복싱 변환의 결과 인 두 개의 참조를 비교하고 있으므로 고유 한 참조입니다.

편집 :을 오버로드하는 유형을 사용 ==하면 다른 동작을 얻을 수 있지만 표현식 의 컴파일 타임 유형을 기반으로합니다 . 예를 들어 다음을 string제공합니다 ==(string, string.

string x = new string("foo".ToCharArray());
string y = new string("foo".ToCharArray());
Console.WriteLine(x == y); // True
Console.WriteLine((object) x == (object) y); // False

여기서 첫 번째 비교는 오버로드 된 연산자를 사용하지만 두 번째 비교는 "기본"참조 비교를 사용합니다.

VB에서 =연산자는 훨씬 더 많은 작업 을 수행합니다. 텍스트를 비교하는 방법에 영향을 줄 수 object.Equals(x, y)있기 때문에 를 사용하는 것과 동등하지 않습니다 Option Compare.

기본적으로 운영자는 같은 방식으로 작동하지 않으며되지 않은 목적으로 같은 방식으로 작동 할 수 있습니다.


17
+1 난 당신이 주위에있을, 당신은 : 신비의 질문에 이러한 종류의 사랑 것 알고 있었다
Abdusalam 벤 하즈

3
@AbZy : =VB에서 수행 한 작업에 대한 자세한 설명을 제공 할 수 있기를 희망 했지만 사양이 명확하지 않습니다.
Jon Skeet

흥미로운 것은 있지만 객체를 동적으로 변경하는 것은 VB와 동일하게 작동합니다.
VladL

4
@VladL : 예. 실행 시간 유형에 따라 bool == bool비교가 수행되기 때문 입니다.
Jon Skeet

1
@Mahdi Lobo가 코드를 제공했을 수도 있지만 Jon의 답변과 달리 그의 대답도 잘못되었습니다.
Servy

79

C # 측면을 설명하는 Jon의 답변 외에도 VB의 기능은 다음과 같습니다.

VB with Option Strict On에서을 통한 비교는 = 항상 값 평등을 테스트하고 참조 평등을 테스트하지 않습니다. 실제로을 정의하지 않기 Option Strict On때문에 전환하면 코드가 컴파일 System.Object되지 않습니다 Operator=. 항상 이 옵션을 설정 해야 합니다. 비너스 플라이 트랩보다 버그를 더 효과적으로 잡을 수 있습니다 (특정 경우이 느슨한 동작이 실제로 올바른 일을하지만). 1

사실,과 Option Strict On에서 C #을 : VB C #을보다 더 엄격한 동작 a == b 중 하나 를 호출을 트리거 SomeType.operator==(a, b)이, (호출하는 것과 같습니다 발동 참조 평등 비교를 존재하지 않는 경우, 또는 object.ReferenceEquals(a, b)).

반면에 VB에서는 비교가 a = b 항상 항등 연산자를 호출합니다. 2 참조 동등 비교를 사용하려면을 a Is b다시 사용해야합니다 (다시 한번 동일 Object.ReferenceEquals(a, b)).


1) 그 이유를 사용하여 좋은 표시이다 Option Strict Off나쁜 생각한다 : 나는 몇 년 전까지 .NET의 공식 출시 이전부터 거의 10 중고 VB.NET을했습니다, 그리고 나는 전혀 생각도 없어 무엇을 a = b함께 수행을 Option Strict Off. 그것은 어떤 종류의 평등 비교를 수행하지만, 정확히 무슨 일이 일어나고, 왜, 전혀 모른다. C #의 dynamic기능 보다 더 복잡 합니다 (잘 문서화 된 API에 의존하기 때문에). MSDN의 내용은 다음과 같습니다.

때문에 Option Strict On제공하는 강력한 입력을 , 데이터 손실을 의도하지 않은 형식 변환, 런타임에 바인딩 것을 허용하지를 방지하고 성능을 향상, 그것의 사용을 적극 권장합니다.

2) Jon은 동등성 비교가 이전 버전과의 호환성 때문에 더 많은 일을하는 곳에서 문자열 예외를 언급했습니다.


4
+1. VB.NET의 설계자들이 VB6과 VBA에서 온 프로그래머들에게 언어를 "정상적으로 작동"시키는 데 성공한 사례라고 생각합니다. OOP가 덜 두드러지고 참조 평등의 개념이 훨씬 덜 중요합니다. VB 코더는 객체 등에 대해 많이 생각하지 않고도 우수한 작업 코드를 작성할 수 있습니다.
John M Gant

5
+1 이것은 실제로 필요한만큼 공짜가 아닙니다. 사용하지 않는 것은 Option Strict On범죄 행위로 간주되어야합니다 ...
Deer Hunter

1
@JohnMGant : 참조 ID의 중요성을 이해하지 못하는 코더는 작동하는 코드를 작성할 수 있지만 실제로 변경 될 수있는 사항, 항상 변경 될 수있는 변경 사항 및 변경 사항이 무엇인지 실제로 알지 못할 수 있습니다. 작동하는 것처럼 보이지만 원치 않는 불쾌한 부작용을 유발합니다 (예 : 동일한 상태를 가진 다른 변경 가능한 객체에 대한 참조가 동일한 객체에 대한 참조가되게 함). 개체가 거의 변경되지 않으면 그러한 변경으로 인해 즉각적인 문제가 발생하지 않지만 나중에 찾기 어려운 버그가 발생할 수 있습니다.
supercat

4

객체 인스턴스는 연산자 "=="와 비교되지 않습니다. "같음"방법을 사용해야합니다. "=="연산자를 사용하면 객체가 아닌 참조를 비교합니다.

이 시도:

public class MyObject
{
    public MyObject(String v)
    {
        Value = v;
    }
    public String Value { get; set; }
}

MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
    Debug.WriteLine("a reference is equal to b reference");
}else{
    Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
    Debug.WriteLine("a object is equal to b object");
} else {
    Debug.WriteLine("a object is not equal to b object");
}

결과 :

a reference is not equal to b reference
a object is not equal to b object

이제 이것을 시도하십시오 :

public class MyObject
{
    public MyObject(String v)
    {
        Value = v;
    }
    public String Value { get; set; }

    public bool Equals(MyObject o)
    {
        return (Value.CompareTo(o.Value)==0);
    }
}
MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
    Debug.WriteLine("a reference is equal to b reference");
}else{
    Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
    Debug.WriteLine("a object is equal to b object");
} else {
    Debug.WriteLine("a object is not equal to b object");
}

결과 :

a reference is not equal to b reference
a object is equal to b object

1
단순히 재정의하지 않았기 때문 operator ==입니다. 해당 연산자를 무시하고 같지 않으면 출력이 반대로됩니다. 의 비교 기준에 고유 한 것이 없으며의 operator ==값 비교에 고유 한 것이 없습니다 Equals. 그들은 평등을 결정하는 두 가지 방법 일뿐입니다. 둘 다 참조 비교의 기본 구현을 가지고 있으며 원하는대로 수행 할 수 있습니다. 다른 차이점은 Equals가상이고 operator ==그렇지 않다는 것입니다.
Servy

1
@Servy : 재정의 할 수 없습니다 . 오버로드== 만 할 수 있습니다 .
Jon Skeet

1
죄송합니다 -1 이 답변은 단순히 틀 렸으며 받아 들여서는 안됩니다.
Konrad Rudolph

어딘가에이 답변을 기다리는 Java 질문이 있습니다.
Chad Schouggins 2013

3

문제는 C #의 == 연산자 가 두 매개 변수 의 컴파일 시간 유형 을 기반으로 정적 메서드 (기술적으로는 아니지만 그렇게 할 수 있음)에 대한 호출이라는 것입니다. 해당 객체의 실제 런타임 유형은 중요하지 않습니다.

해당 컴파일 시간 유형을 기반으로 컴파일러는 operator ==사용할 구현을 결정 합니다. 기본 object구현을 사용하거나 언어에서 제공하는 숫자 과부하 중 하나를 사용하거나 사용자 정의 구현 일 수 있습니다.

VB는 컴파일 타임에 구현을 결정하지 않는다는 점에서 VB와 다릅니다. 런타임까지 대기 ==하고 사용해야 하는 연산자의 구현을 판별하기 위해 제공되는 두 개의 매개 변수를 검사합니다 .

코드에 부울 값이 포함되어 있지만 유형이 변수에 있습니다 object. 때문에 변수가 형이고 object, C # 컴파일러는 사용 object구현 ==비교 참조 하지 객체 인스턴스. 부울 값은 상자이므로 값이 같더라도 동일한 참조를 갖지 않습니다.

VB 코드는 변수의 유형을 신경 쓰지 않습니다. 런타임까지 기다렸다가 두 변수를 확인하고 변수가 실제로 부울 유형 인 것을 확인 하여 부울 ==연산자 구현을 사용합니다 . 이 구현은 참조가 아닌 부울 값을 비교합니다 (부울은 해당 연산자를 호출하기 전에 상자가 풀리므로 참조 비교는 더 이상 의미가 없습니다). 부울 값이 같으므로 true를 리턴합니다.


C #에서는 괜찮습니다. =VB에서 정확히 무엇 을 말할지 정확히 알지 못합니다 .
Jon Skeet

@JonSkeet Fair로 충분합니다.
Servy

msdn.microsoft.com/en-us/library/cey92b0t(v=vs.110).aspx 섹션에서 "관계 비교 연산자와 유형이없는 프로그래밍" =과 같은 다른 모든 관계 비교 연산자와 함께 <, >=등 운전자의 양쪽 또는 양쪽이이면 특별한 취급이 필요 Object합니다. 이 특별한 처리는 Variant.NET VB 이전과 같은 유형을 사용하는 데 익숙한 VB6 프로그래머 ObjectVariant이전에 사용했던 방식으로 VB.Net에서 사용할 수 있도록하기 위해 수행 됩니다 .
rskar

다시 말해서 과부하의 영향 을 피하고 Option Strict OnVB =ObjectString 또는 숫자에 도달 할 때까지 unboxing쪽으로 편향되어 있습니다.
rskar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.