2011-02-17 2 views
4

다음 코드 스 니펫이 있지만 잘못된 출력이 표시됩니다. Object에 같은 두 숫자를 캐스팅하면 왜 동일하지 않게되는 걸까요?

class Program 
    { 
     static void Main(string[] args) 
     { 
      var i = 10000; 
      var j = 10000; 
      Console.WriteLine((object) i == (object) j); 


     } 
    } 

나는 진정한 기다리고 있었다 그러나 나는 각 변수에 대한 새로운 인스턴스를 생성하는 당신은 (객체 캐스트를 통해) 숫자를 권투하는 거짓

+11

올바른 결과를 얻고 있습니다 ... 잘못된 기대를 가지고 있습니다. –

+0

@ 존 Skeet : 주석 주셔서 감사합니다. –

+0

@ 존 Skeet : 코드 또는 의견, 당신은 흔들리고있다. – Mohanavel

답변

21

을 얻고있다. 객체에 대한 == 연산자는 객체의 신원 (또한 참조 평등라고도 함)과 (인스턴스가 동일하지 않기 때문에) 그래서 당신은 false을보고있는

가 올바르게 Object.Equals(i, j) 또는 i.Equals(j) 사용할 수 이러한 개체를 비교하는 기준으로합니다. 이는 객체의 실제 런타임 인스턴스가 이고 Equals() 메소드가 정수에 대해 올바른 동등 의미를 갖고 있기 때문에 작동합니다.

+0

@marcind : 우리는 버그라고 말할 수 있을까요? –

+1

@geek : 코드의 버그. 일반적인'object' 인스턴스에 대한'=='의 동작은 의미가 있습니다 (여러분이 비교하고있는 것에 대해서는 아무것도 * 알지 못하므로 대안이 없습니다) 그리고 여러분은 명시 적으로 객체를 요청했습니다. – delnan

+1

결과로 'true'를 얻으 려한다면 코드에 버그가 있다고 말할 수 있습니다. – BrokenGlass

2

두 개의 서로 다른 개체를 비교하기 때문에 그 이유는 무엇입니까?

5

기본적으로 ReferenceEquals을 호출하는 ==을 사용하고 있습니다. 다음을 사용해야합니다.

Console.WriteLine(((object)i).Equals((object)j)); 
1

두 개의 서로 다른 개체이며 서로 동일하지 않습니다. 그들의 가치는 동일합니다.

1

연산자가 오버로드되지 않고 오버로드됩니다. 즉, 호출 될 실제 메소드는 런타임이 아닌 컴파일 타임에 결정됩니다. 이 차이를 이해하려면이처럼 생각해야합니다

MyBase a = new A(); 
MyBase b = new B(); 

a.DoSomething(); // prints "A" 
b.DoSomething(); // prints "B" 

은 어떻게됩니까 :

당신이하는 A의 인스턴스와 B를 만들 수 있습니다 지금

public class MyBase 
{ 
    public virtual void DoSomething() { Console.WriteLine("Base"); } 
} 

public class A : MyBase 
{ 
    public override void DoSomething() { Console.WriteLine("A"); } 
} 

public class B : MyBase 
{ 
    public override void DoSomething() { Console.WriteLine("B"); } 
} 

다음과 같은 코드가 있다고 가정 MyBase의 모든 인스턴스에는 호출되어야하는 DoSomething()의 실제 구현을 가리키는 vtable에 대한 숨겨진 참조가 포함되어 있습니다. 따라서 런타임에서 을 a에 호출해야하는 경우 vtable은 a이고 버전은 "A"입니다. 중요한 부분은 이것이 런타임에 발생한다는 것입니다.

이제 메서드를 오버로드하면 이름이 같지만 서명이 다른 메서드를 만듭니다.

public class C 
{ 
    public void Print(string str) { Console.WriteLine("string: " + string); } 
    public void Print(int i) { Console.WriteLine("int: " + i); } 
    public void Print(object obj) { Console.WriteLine("object: " + obj.ToString()); } 
} 

var c = new C(); 
c.Print("1"); // string: 1 
c.Print(1); // int: 1 
c.Print((object)1); // object: 1 

이번에는 컴파일러가 런타임 대신 어떤 메소드가 호출되는지 결정합니다. 그리고 컴파일러는별로 똑똑하지 않습니다. (object)1을 보면 개체에 대한 참조가 표시되고 컴파일러는 개체를 인수로 사용할 수있는 Print()의 버전을 찾으려고 시도합니다.

간혹 컴파일러에서 두 가지 버전을 사용할 수 있습니다. 예를 들어 "1"은 문자열이지만 객체이기도하므로 Print()의 첫 번째 버전과 세 번째 버전 모두 문자열을 허용 할 수 있습니다. 이 경우 컴파일러는 가장 구체적인 인수 유형이있는 버전을 선택합니다.때로는 컴파일러는 다음 예에서와 같이, 선택할 수 없습니다 :이 경우

public static void Print(string a, object b) { Console.WriteLine("V1"); } 
public static void Print(object a, string b) { Console.WriteLine("V2"); } 

Print("a", "b"); // does this print "V1" or "V2"? 

를 버전 중 어느 것도 다른 것보다 더 구체적인 없기 때문에 컴파일러는 컴파일러 오류 발생 : 통화 사이 모호을 'Test.Program.Print (문자열, 개체)'및 'Test.Program.Print (개체, 문자열)'

앞서 말했듯이 == 연산자가 오버로드됩니다. 즉, 컴파일러는 사용할 버전을 선택합니다. 가장 일반적인 버전은 두 피연산자가 모두 Object 인 버전입니다. 이 버전은 참조를 비교합니다. 따라서 (object) i == (object) j이 false를 반환합니다.

관련 문제