문제

다음 프로그램은 인쇄합니다

A:C(A,B)
B:C(A,B)

(해야 할 때)

public interface I
{
    string A();
}

public class C : I
{
    public string A()
    {
        return "A";
    }

    public string B()
    {
        return "B";
    }
}

public class A
{
    public virtual void Print(C c)
    {
        Console.WriteLine("A:C(" + c.A() + "," + c.B() + ")");
    }
}

public class B : A
{
    public new void Print(C c)
    {
        Console.WriteLine("B:C(" + c.A() + "," + c.B() + ")");
    }

    public void Print(I i)
    {
        Console.WriteLine("B:I(" + i.A() + ")");
    }
}

class Program
{
    public static void Main(string[] args)
    {
        A a = new A();
        B b = new B();
        C c = new C();
        a.Print(c);
        b.Print(c);
    }
}

그러나 키워드를 '새'를 변경하면 클래스 B에서 '재정의'로 변경합니다.

    public override void Print(C c)

갑작스런 프로그램이 모두 인쇄되기 시작합니다.

A:C(A,B)
B:I(A)

왜요?

도움이 되었습니까?

해결책

이것은 과부하 된 방법이 어떻게 해결되는지와 관련이 있습니다.

효과적으로 (다소 단순화), 컴파일러는 먼저 선언 된 표현 유형 (b)을보고 후보 방법을 찾습니다. 이 유형에서 처음 선언됩니다. 적절한 메소드가있는 경우 (즉, 모든 인수가 메소드의 매개 변수 유형으로 변환 될 수있는 경우) 그렇지 않습니다 부모 유형을보십시오. 이는 초기 선언이 부모 유형에있는 재정의 메소드가 파생 유형에 "새로 선언 된"적절한 방법이 있다면 검토를 얻지 못한다는 것을 의미합니다.

다음은 약간 간단한 예입니다.

using System;

class Base
{
    public virtual void Foo(int x)
    {
        Console.WriteLine("Base.Foo(int)");
    }
}

class Derived : Base
{
    public override void Foo(int x)
    {
        Console.WriteLine("Derived.Foo(int)");
    }

    public void Foo(double d)
    {
        Console.WriteLine("Derived.Foo(double)");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        d.Foo(10);
    }
}

이 지문 Derived.Foo(double) - 컴파일러가 유형의 매개 변수와 일치하는 메소드가 있다는 것을 알고 있지만 int, 그리고 인수는 유형입니다 int, 그리고 전환 int 에게 int 전환보다 "더 나은"것입니다 int 에게 double, 사실 만 Foo(double) 방법은 원래입니다 선언 안에 Derived 컴파일러가 무시 함을 의미합니다 Foo(int).

이것은 매우 놀랍습니다. 왜 그런지 알 수 있습니다. Derived 무시하지 않았습니다 Foo - 그렇지 않으면 기본 클래스에 새롭고 더 구체적인 방법을 도입하면 예기치 않게 행동이 변경 될 수 있습니다. Derived 여기 알고 있습니다 ~에 대한 Base.Foo(int) 그것을 무시하고 있습니다. 이것은 C# 디자이너가 잘못된 결정을 내렸다고 생각하는 (상대적으로 적은) 포인트 중 하나입니다.

다른 팁

알았어 그래서

    public new void Print(C c)
    {
        Console.WriteLine("B:C(" + c.A() + "," + c.B() + ")");
    }

    public void Print(I i)
    {
        Console.WriteLine("B:I(" + i.A() + ")");
    }

이것은 인쇄에 대한 새로운 방법을 선언합니다. 이제 B가 A에서 물려 받기 때문에 새로운 방법을 두 번 호출합니다. 메소드를 지나가면 A를 호출 할 때 메소드 서명을 변경하지만 B 서명을 호출하면 자체 메소드 서명이 있습니다.

분명하지만 좋은 질문을 설명하고 있는지 확실하지 않습니다.

새로운 사용 :

A와 B는 인쇄 방법의 동일한 구현을 얻습니다.

오버라이드 사용 :

A는 B에 대한 다른 메소드 서명을 가지고 있습니다.

새로운 것을 사용하면 기본적으로 다음과 같습니다.

    public void Print(I i)
    {
        Console.WriteLine("B:I(" + i.A() + ")");
    }

이것은 좋은 질문이었습니다.
모든 답변은 여기에서 찾을 수 있습니다.http://msdn.microsoft.com/en-us/library/6fawty39(vs.80).aspx

그것의 요점은 이것입니다.

... C# 컴파일러는 먼저 [FunctionName]이 원래 [파생 클래스]에서 선언 된 [functionName] 버전과 호환성을 만듭니다. 재정의 방법은 클래스에서 선언 된 것으로 간주되지 않으며, 기본 클래스에서 선언 된 메소드의 새로운 구현입니다. C# 컴파일러가 메소드 호출을 [파생 클래스]의 원래 메소드와 일치시킬 수없는 경우에만 호출을 동일한 이름과 호환 매개 변수로 재정의 메소드와 일치 시키려고합니다.

따라서 인수 "C"와 일치하는 파생 클래스에 새로운 메소드 인쇄 (I I)가 있기 때문에 (C 구현 I), 그 방법은 "재정의"메소드보다 우선합니다.

메소드를 "새"로 표시하면 파생 클래스에서 구현되는 것으로 간주되며 인쇄 (C C) 메소드는 매개 변수 "C"와 더 밀접하게 일치하므로 우선합니다.

이것은 적어도 방법에 대한 질문입니다. 과부하 C#에서 작동합니다. 여기서 흥미로운 상황을 강조했다고 생각합니다 ...

첫 번째 경우 (사용 사용 new 메소드에 대한 키워드), 컴파일러는 사용하기로 결정합니다. Print 유형이 전달 된 매개 변수의 매개 변수와 함께하는 메소드 오버로드 (즉, 암시 적 변환이 필요하지 않음)이지만 인터페이스로의 암시 적 변환은 컴파일러가 선택 해야하는 경우 필요합니다. Print 유형 I의 인수를 취하는 메소드 - 즉, 더 "명백한"메소드 과부하를 선택합니다.

두 번째 경우 (사용 사용 override 메소드에 대한 키워드), 컴파일러는 과부하를 사용하기로 결정합니다. Print 유형 I의 매개 변수로 Print(C c) 클래스 B의 메소드 오버로드는 상위 클래스 A에서 효과적으로 정의되어 Print(I i) 메소드 오버로드 실제로 가장 높은 수준의 오버로드는 가장 직접적인 오버로드입니다. 즉, 컴파일러가 찾은 첫 번째 오버로드입니다.

바라건대 이것은 당신이 이해하는 데 도움이 될 것입니다. 포인트가 더 필요한지 알려주세요 ...

참고 : 컴파일러가 이런 일을한다고 말하는 것이 틀렸다면, 그것이 컴파일러이든 CLR/JIT인지에 관계없이 논쟁을 거의하지 않지만 저를 수정하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top