연산자가 오버로드되지 않고 오버로드됩니다. 즉, 호출 될 실제 메소드는 런타임이 아닌 컴파일 타임에 결정됩니다. 이 차이를 이해하려면이처럼 생각해야합니다
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를 반환합니다.
올바른 결과를 얻고 있습니다 ... 잘못된 기대를 가지고 있습니다. –
@ 존 Skeet : 주석 주셔서 감사합니다. –
@ 존 Skeet : 코드 또는 의견, 당신은 흔들리고있다. – Mohanavel