57

다음 코드를 감안할 때 클래스 A의 메소드 X 버전을 호출 할 수있는 방법이 있습니까?

class A
{
  virtual void X() { Console.WriteLine("x"); }
}

class B : A
{
  override void X() { Console.WriteLine("y"); }
}

class Program
{
  static void Main()
  {
    A b = new B();
    // Call A.X somehow, not B.X...
  }

6 답변


95

C #언어 구문을 사용하면 명시 적으로 기본 함수를에서 호출 할 수 없습니다.외부~의 범위A또는B. 정말로 그렇게해야한다면 디자인에 결함이 있습니다. 즉, 처음에는 함수가 가상 적이 어서는 안되며, 기본 함수의 일부는 별도의 비 가상 함수로 추출되어야합니다.

너는 ~ 할 수있어.내부B.X 그러나 A.X를 부르십시오.

class B : A
{
  override void X() { 
    base.X();
    Console.WriteLine("y"); 
  }
}

그러나 그것은 다른 것입니다.

Sasha Truf가 지적한대로이 대답, 당신은 IL을 통해 그것을 할 수 있습니다. 코멘트에서 mhand가 지적했듯이, 아마도 이것을 반영하여 성취 할 수도 있습니다.


  • (안녕하세요, 기록을 위해 누군가 내가 추가 한 바보 같은 트릭 태그를 삭제 한 다음 누군가가이를 지적한 댓글을 삭제하여 내가 실제로 이것을 원하거나 필요로하는 것처럼 보이게 만듭니다. 사람들이 SO에서 만들고 싶어하는 벙어리 편집에 대한 알림을받는 것이 유용 할 것입니다.) - mackenir
  • B 내부에서 A.X ()를 호출하면 한 번 호출해야하는 것을 볼 수있는 유일한 상황입니다. 기본 클래스 멤버가있는 복사 메서드가 있다고 가정 한 다음 새 멤버에 복사 기능을 추가하고 base.copy ()를 호출하여 모두 복사되도록합니다. - steviesama
  • 재미있게, 나는 그것이 반사를 통해 성취 될 수 있다고 생각 했을까? - mhand
  • 테스트를 작성할 때, 다형성 트릭을 통해 동작을 수정하기를 원하는 경우가 드문 일이 아닙니다. 따라서 오버라이드 된 메서드 내에서 기본 메서드를 호출해야하는 것은 반드시 잘못된 디자인을 나타내는 것은 아니며 테스트하기 어려운 디자인을 나타낼 수 있습니다. 나는 그러한 요구 때문에 정확하게 당신의 대답을 발견했습니다. - Pétur Ingi Egilsson
  • @ P é turIngiEgilsson - " 재정의 된 메소드 내에서 기본 메소드 호출 "을 작성할 때 기본 메소드를 호출하는 OP와 어떤 점에서 차이가 있다고 생각합니다.외부파생 클래스 내가 당신의 의견을 이해함에 따라, 당신은 그 방법을내부내가 지적한 파생 클래스가 가능합니다. - Pete

11

C #에서는 할 수 없지만 MSIL은 편집 할 수 있습니다.

귀하의 일리노이 코드본관방법:

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 1
    .locals init (
        [0] class MsilEditing.A a)
    L_0000: nop 
    L_0001: newobj instance void MsilEditing.B::.ctor()
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: callvirt instance void MsilEditing.A::X()
    L_000d: nop 
    L_000e: ret 
}

L_0008의 opcode를에서 (으)로 변경해야합니다.callvirt요구

L_0008: call instance void MsilEditing.A::X()


9

당신은 할 수 없으며 그렇게해서는 안됩니다. 그것이 다형성을위한 것이며, 그래서 각 객체는 "기본"일을 수행하는 고유 한 방법을 가지고 있습니다.


8

당신이 할 수는 있지만, 당신이 지정한 시점에는 아닙니다. 다음의 맥락에서B, 당신은A.X()전화 걸기base.X().


4

나는 지금 역사 문제에 대해 알고있다. 그러나 다른 Google 직원에게 : 이와 비슷한 것을 쓸 수 있습니다. 그러나이를 위해서는 기본 라이브러리를 변경해야 외부 라이브러리에서 쓸모 없게됩니다.

class A
{
  void protoX() { Console.WriteLine("x"); }
  virtual void X() { protoX(); }
}

class B : A
{
  override void X() { Console.WriteLine("y"); }
}

class Program
{
  static void Main()
  {
    A b = new B();
    // Call A.X somehow, not B.X...
    b.protoX();


  }


2

메서드가 파생 클래스에서 다음과 같이 선언되면 불가능합니다.overrides. 이렇게하려면 파생 클래스의 메서드를 다음과 같이 선언해야합니다.new:

public class Base {

    public virtual string X() {
        return "Base";
    }
}
public class Derived1 : Base
{
    public new string X()
    {
        return "Derived 1";
    }
}

public class Derived2 : Base 
{
    public override string X() {
        return "Derived 2";
    }
}

Derived1 a = new Derived1();
Base b = new Derived1();
Base c = new Derived2();
a.X(); // returns Derived 1
b.X(); // returns Base
c.X(); // returns Derived 2

여기에 바이올린보기

연결된 질문


관련된 질문

최근 질문