2017-01-31 4 views
14

나는 무슨 일이 일어나고 있는지 이해하지 못한다는 것을 이해하기 시작했습니다. 그것은상속 된 클래스의 메서드 오버로드

public void Method(B a)

대신

public void Method(D a)

그것은 놀라운 인쇄됩니다

public class Base 
{ 
    public void Method(D a) 
    { 
     Console.WriteLine("public void Method(D a)"); 
    } 
} 

public class Derived: Base 
{ 
    public void Method(B a) 
    { 
     Console.WriteLine("public void Method(B a)"); 
    } 
} 

public class B { } 

public class D: B { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Derived derived = new Derived(); 
     D d = new D(); 

     derived.Method(d); 
    } 
} 

: C#에서 다음과 같은 문제가있다. 이 동작의 이유는 메소드 테이블의 구현이라고 생각합니다. CLR은 현재 형식에서 해당 메서드를 찾으면 기본 클래스의 메서드를 검색하지 않습니다. 나는 그들이 성과를 향상 시키려고 노력하고 있다고 생각한다. 이

public void Method(B a)

대신

public override void Method(D a)

그것은 끔찍한 매우 unpred의 인쇄됩니다

public class Base 
{ 
    public virtual void Method(D a) 
    { 
     Console.WriteLine("public void Method(D a)"); 
    } 
} 

public class Derived: Base 
{ 
    public override void Method(D a) 
    { 
     Console.WriteLine("public override void Method(D a)"); 
    } 

    public void Method(B a) 
    { 
     Console.WriteLine("public void Method(B a)"); 
    } 

} 

public class B { } 

public class D: B { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Derived derived = new Derived(); 
     D d = new D(); 

     derived.Method(d); 
    } 
} 

과 :

는하지만 난 다음 코드로 완전히 실망했다 상상할 수있는.

누구든지 설명 할 수 있습니까?

메서드 테이블에 현재 형식 (오버라이드 메서드 제외)으로 만 구현 된 메서드가 있고 호출 할 수있는 메서드를 찾자 마자 CLR이 해당 메서드를 찾는 것을 중지한다고 가정합니다. 내가 맞습니까?

+3

메소드 테이블에서 메소드가 호출 된 특정 유형의 시그니처가있는 메소드를 찾고 있는데 상속에 따라 d가 b이기 때문에 일치를 찾습니다.이 메소드는 무시 된 메소드를 무시합니다. –

+0

@EhsanSajjad 질문 * 왜 * 다른 것보다 과부하를 선택하는 이유입니다. 둘 다 유효한 메서드 호출이지만 컴파일러는 다른 메서드를 하나씩 선택합니다. – Servy

+1

'호출 할 수있는 메소드가 발견되는 즉시 CLR은 해당 메소드를 찾지 않습니다. 내가 맞습니까? '이것은 CLR과 아무 관련이 없습니다. 이것은 런타임에 의한 결정이 아닌 C# 사양에 기반한 C# 컴파일러의 전체 컴파일 시간 결정입니다. – Servy

답변

15

나는 무슨 일이 일어나고 있는지 이해하지 못한다는 것을 이해하기 시작했습니다.

따라서 지혜가 시작됩니다.

매우 예측할 수 없습니다.

아니요. 대조적으로이 기능은 으로 설계되어 예측할 수 없으며 으로 인해 취약한 기본 클래스 오류의 원인이 제거됩니다.

누구나 설명 할 수 있습니까?

내 2007 기사를 참조하십시오.

https://blogs.msdn.microsoft.com/ericlippert/2007/09/04/future-breaking-changes-part-three/

짧은 버전은 생각입니다 : 파생 클래스의 메소드는 항상 기본 클래스의 방법보다 더 나은; 파생 클래스를 작성한 사람 은 객체 의미에 대한 자세한 내용을 알고이고 은 기본 클래스를 작성한 사람보다 더 구체적인 케이스을 처리합니다.

Servy는 두 번째 사항을 다루지 못했다고 지적합니다. 파생 클래스에서 재정의가 "파생 클래스에서" "D"메서드를 만들지 않는 이유는 무엇입니까?

가상 방법은 그들이, 그들은 가장 최근에를 오버라이드 (override) 된 클래스의하지 선언 된 클래스의 방법으로 간주됩니다. 왜? 은 오버레이를 선택했기 때문에 클래스의 구현 세부 사항이며 공용 표면 영역의 일부가 아닙니다.

내 말은 생각해보십시오. 몇 가지 코드를 작성하고 작동하고 나서이 코드에서 어딘가의을 새로 만들거나 (예전의 코드를 제거하십시오)이 유형 계층 구조에서 갑자기 변경하면 과부하 해결 다른 곳? 이것이 바로 C#이 제거하려고하는 종류의 깨지기 쉬운 현상입니다.

팀에서 코드를 편집하는 세계에서 C#은 매우 신중하게 설계되었습니다. . 기괴하게 많은 현대 언어가 마치 한 사람이 모든 코드를 작성하고 처음으로 올바르게 작성한 것처럼 설계되었습니다. 현실적이지 않습니다. C#의 특이한 기능 중 일부는 발견 한 것과 마찬가지로 다른 사람들이 기본 클래스를 편집하고있을 때도 프로그램 동작을 예측 가능하게 유지하는 데 도움이됩니다.

+1

@Servy : 가상 메서드는 그것을 오버로드하는 형식이 아니라 선언하는 형식의 메서드로 간주됩니다. 그러나 그것은 미묘한 점입니다. 대답에 메모를 추가하겠습니다. –

1

여기서 혼란 스러울 수 있습니다. 에릭의 대답은 예를 들어 더 잘 설명 될 수 있습니다. 다음과 같이 코드를 변경 한 경우 ...

public class Base 
{ 
    public virtual void Method(D a) 
    { 
     Console.WriteLine("public void Method(D a)"); 
    } 

    public void Method(B a) 
    { 
     Console.WriteLine("public void Method(B a)"); 
    } 
} 

public class Derived : Base 
{ 
    public override void Method(D a) 
    { 
     Console.WriteLine("public override void Method(D a)"); 
    } 

} 

public class B { } 

public class D : B { } 

출력이 "public override void Method (D a)"가됩니다.

왜? 파생 동급 방법은 방법 (D) 및 방법 모두로

적용 할 경우

에릭의 기사에서 언급 한 바와 같이

... 기본 클래스에서

방법은 후보 없습니다 (B)가 기본 클래스에 있으면 메서드 (D)가 파생 클래스에서 오버라이드되어 출력됩니다.

초보자 용으로 꽤 혼란 스럽습니까? 경험 많은 개발자도 꽤 혼란 스럽습니다. 여기에서 핵심 포인트는 나쁜 디자인이라고 생각합니다. CLR 또는 C# 컴파일러에 대해 이야기하는 것이 아니며 여기에서 당신을 도울 수있는 최선의 방법입니다. 수업에 대해 이야기하고 있습니다. 당신의보기에서.

OOP를 처음 접하는 많은 사람들이 흔히 범하는 실수는 상속 인 새로운 장난감을 과도하게 사용하는 것입니다. 상속은 종종 OOD에서 사용되는 선호 관계가 아닙니다. OOP 디자인 패턴을 공부하기 시작할 때 많은 패턴이 상속을 사용하지 않는다는 것을 알게 될 것입니다.

왜? 귀하의 예제는 상속을 사용할 때 생성 될 수있는 혼란의 종류를 보여주기 때문에 Fragile Inheritance으로 알려져 있습니다. 디자인 패턴은 더 자주 집합과 구성을 사용하여 문제 공간을보다 실행 가능하고 확장 가능하며 관리 가능한 솔루션으로 나눕니다.

상속은 가장 강력한 것들과 마찬가지로 강력한 구성이며 사소하고 조심스럽게 사용해야합니다.