[c#] base.base.method ()를 호출하는 방법?

// Cannot change source code
class Base
{
    public virtual void Say()
    {
        Console.WriteLine("Called from Base.");
    }
}

// Cannot change source code
class Derived : Base
{
    public override void Say()
    {
        Console.WriteLine("Called from Derived.");
        base.Say();
    }
}

class SpecialDerived : Derived
{
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.Say();
    }
}

class Program
{
    static void Main(string[] args)
    {
        SpecialDerived sd = new SpecialDerived();
        sd.Say();
    }
}

결과는 다음과 같습니다.

Special Derived에서 호출되었습니다.
Derived에서 호출되었습니다. / * 이것은 예상되지 않습니다 * /
Base에서 호출되었습니다.

중산층 “Derived”의 메서드가 호출되지 않도록 SpecialDerived 클래스를 어떻게 다시 작성할 수 있습니까?

업데이트 :
Base 대신 Derived에서 상속하려는 이유는 Derived 클래스에 다른 많은 구현이 포함되어 있기 때문입니다. base.base.method()여기서 할 수 없기 때문에 가장 좋은 방법은 다음을 수행하는 것입니까?

// 소스 코드를 변경할 수 없습니다.

class Derived : Base
{
    public override void Say()
    {
        CustomSay();

        base.Say();
    }

    protected virtual void CustomSay()
    {
        Console.WriteLine("Called from Derived.");
    }
}

class SpecialDerived : Derived
{
    /*
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.Say();
    }
    */

    protected override void CustomSay()
    {
        Console.WriteLine("Called from Special Derived.");
    }
}



답변

사람들이 많은 시간이 지난 후에도 여전히이 질문에 답하기 때문에 여기에 추가하고 싶습니다. 물론 나쁜 습관이지만 원칙적으로 작성자가 원하는 것을 수행하는 것은 여전히 ​​가능합니다.

class SpecialDerived : Derived
{
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        var ptr = typeof(Base).GetMethod("Say").MethodHandle.GetFunctionPointer();
        var baseSay = (Action)Activator.CreateInstance(typeof(Action), this, ptr);
        baseSay();
    }
}


답변

이것은 나쁜 프로그래밍 관행이며 C #에서는 허용되지 않습니다. 그것은 나쁜 프로그래밍 관행입니다.

  • 그랜드베이스의 세부 사항은베이스의 구현 세부 사항입니다. 당신은 그들에게 의존해서는 안됩니다. 기본 클래스는 그랜드베이스 위에 추상화를 제공합니다. 이를 피하기 위해 우회를 구축하는 것이 아니라 추상화를 사용해야합니다.

  • 이전 요점의 특정 예를 설명하기 위해 : 허용되는 경우이 패턴은 취약한 기본 클래스 오류에 취약한 코드를 만드는 또 다른 방법입니다. C에서 파생 B되는 파생 항목을 가정합니다 A. 의 메서드를 호출하는 C데 사용 base.base되는 코드 입니다 A. 다음의 저자 B들은 수업 시간에 너무 많은 기어를 넣어 것을 실현 B하고, 더 좋은 방법은 중간 클래스 확인하는 것입니다 B2그에서 유래 A하고, B도출에서을 B2. 변경 후 코드 인 C은 에서 가 B2아니라에서 메서드를 호출합니다A 않기 때문C 의 구현 세부 사항 B, 즉 직접 기본 클래스가 다음과 같다고 가정A, 결코 변하지 않을 것입니다. C #의 많은 디자인 결정은 다양한 종류의 취약한 기본 오류의 가능성을 완화하는 것입니다. base.base불법화 하기로 한 결정 은 이러한 실패 패턴의 특정 특징을 완전히 방지합니다.

  • 당신은 당신이하는 것을 좋아하고 재사용하고 확장하기를 원하기 때문에 당신의 기지에서 파생되었습니다. 그것이하는 일이 마음에 들지 않고 함께 일하는 것보다 그것을 해결하고 싶다면, 왜 처음부터 그 일에서 파생 되었습니까? 그 기능이 사용하고 확장하려는 경우 그랜드베이스에서 직접 파생하십시오.

  • 기본은 기본이 그랜드베이스의 방법을 사용하는 방법에 대한 세부 사항에 의해 유지되는 보안 또는 의미 적 일관성 목적을 위해 특정 불변성을 요구할 수 있습니다. 기본의 파생 클래스가 이러한 불변성을 유지하는 코드를 건너 뛰도록 허용하면 기본이 일관성이없고 손상된 상태가 될 수 있습니다.


답변

C #에서는 할 수 없습니다. IL에서는 실제로 지원됩니다. 부모 클래스에 가상이 아닌 호출을 할 수 있습니다.하지만하지 마십시오. 🙂


답변

대답은 (당신이 찾고있는 것이 아님을 알고 있습니다) :

class SpecialDerived : Base
{
    public override void Say()
    {
        Console.WriteLine("Called from Special Derived.");
        base.Say();
    }
}

사실, 당신은 상속받은 클래스와 직접적인 상호 작용 만 할 수 있습니다. 해당 클래스를 계층으로 생각하십시오. 파생 클래스에 원하는만큼 또는 부모의 기능을 제공하는 것입니다.

편집하다:

귀하의 편집은 작동하지만 다음과 같은 것을 사용할 것이라고 생각합니다.

class Derived : Base
{
    protected bool _useBaseSay = false;

    public override void Say()
    {
        if(this._useBaseSay)
            base.Say();
        else
            Console.WriteLine("Called from Derived");
    }
}

물론 실제 구현에서는 확장 성과 유지 관리를 위해 다음과 같은 작업을 수행 할 수 있습니다.

class Derived : Base
{
    protected enum Mode
    {
        Standard,
        BaseFunctionality,
        Verbose
        //etc
    }

    protected Mode Mode
    {
        get; set;
    }

    public override void Say()
    {
        if(this.Mode == Mode.BaseFunctionality)
            base.Say();
        else
            Console.WriteLine("Called from Derived");
    }
}

그러면 파생 클래스가 부모의 상태를 적절하게 제어 할 수 있습니다.


답변

단순히 자식 클래스를 특정 부모 클래스로 캐스팅하고 특정 구현을 호출하지 않는 이유는 무엇입니까? 이것은 특수한 상황이며 특수한 경우 솔루션을 사용해야합니다. new그래도 자식 메서드 에서는 키워드 를 사용해야합니다 .

public class SuperBase
{
    public string Speak() { return "Blah in SuperBase"; }
}

public class Base : SuperBase
{
    public new string Speak() { return "Blah in Base"; }
}

public class Child : Base
{
    public new string Speak() { return "Blah in Child"; }
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Child childObj = new Child();

        Console.WriteLine(childObj.Speak());

        // casting the child to parent first and then calling Speak()
        Console.WriteLine((childObj as Base).Speak());

        Console.WriteLine((childObj as SuperBase).Speak());
    }
}


답변

public class A
{
    public int i = 0;
    internal virtual void test()
    {
        Console.WriteLine("A test");
    }
}

public class B : A
{
    public new int i = 1;
    public new void test()
    {
        Console.WriteLine("B test");
    }
}

public class C : B
{
    public new int i = 2;
    public new void test()
    {
        Console.WriteLine("C test - ");
        (this as A).test();
    }
}


답변

그랜드베이스 함수를 호출하기 위해 첫 번째 수준 파생 클래스에서 간단한 함수를 만들 수도 있습니다.