// 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();
}
}
답변
그랜드베이스 함수를 호출하기 위해 첫 번째 수준 파생 클래스에서 간단한 함수를 만들 수도 있습니다.