31

아래 코드에서 두 가지 방법으로 부모 메소드 인 methodTwo에 액세스하려고 시도했지만 결과는 항상 2였습니다.이 두 클래스를 수정하지 않고 ChildClass 인스턴스에서 1 개의 결과를 얻는 방법이 있습니까?

class ParentClass
{
    public int methodOne()
    {
        return methodTwo();
    }

    virtual public int methodTwo()
    {
        return 1;
    }
}

class ChildClass : ParentClass
{
    override public int methodTwo()
    {
        return 2;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var a = new ChildClass();
        Console.WriteLine("a.methodOne(): " + a.methodOne());
        Console.WriteLine("a.methodTwo(): " + a.methodTwo());
        Console.WriteLine("((ParentClass)a).methodTwo(): "
         + ((ParentClass)a).methodTwo());
        Console.ReadLine();
    }
}

최신 정보ChrisW가 올린 글 :

수업 외에서 나는 잘 모른다.   어떤 쉬운 방법; 하지만 아마도, 나는하지 않습니다.   시도하면 어떻게되는지 알 수 있습니다.   reflection : Type.GetMethod를 사용하십시오.   methodInfo를 찾는 메소드   에있는 방법과 관련된   ParentClass를 호출 한 다음 호출   MethodInfo.Invoke

그 대답은 삭제되었습니다. 그 호크가 호기심에 효과가 있는지 궁금합니다.


8 답변


35

일리노이 수준에서 아마 당신은call오히려callvirt, 그리고 일을 끝내라 - 그러나 우리가 C #으로 제한된다면, -p (편집하다꿰매다! 런타임이 멈 춥니 다.VerificationException: "작업으로 인해 런타임이 불안정해질 수 있습니다."; 그 사람을 제거하다virtual그리고 그것은 잘 작동합니다. 반으로 너무 영리 해 ...)

내부ChildClass유형, 당신은 사용할 수 있습니다base.methodTwo()- 그러나 이것은 외부에서 가능하지 않습니다. 한 단계 이상 내려갈 수 없습니까?base.base.Foo()지원하다.

그러나 메소드 숨기기를 사용하여 다형성을 비활성화하면대답당신이 원하지만, 나쁜 이유로 :

class ChildClass : ParentClass
{
    new public int methodTwo() // bad, do not do
    {
        return 2;
    }
}

변수가 정의되어 있는지 여부에 따라 동일한 객체에서 다른 답변을 얻을 수 있습니다.ChildClass또는ParentClass.


  • " 새 " 이 경우에 좋지 않니? " 새 " 좋은가요? - Peter Huber
  • @PeterHuber는 다형성을 깨뜨리기 때문에; 주요 유스 케이스new이 시나리오에서는 유형을보다 전문화하기위한 것입니다. 예를 들어,DbCommand~을 가지고있다.public DbParameterCollection Parameters {get;}-하지만SqlCommand : DbCommand~을 가지고있다.public new SqlParameterCollection Parameters {get;}. 두 API 모두 동일한 값을 반환합니다.(별도의protected abstract속성, 즉DbParameterCollection- 그 값은 항상있다에이SqlParameterCollection) -보다 구체적인 유형은보다 구체적인 방식으로 그것을 노출합니다 - Marc Gravell
  • @MarcGravell : 정보를 주셔서 감사합니다. 실제로 자세히 이해하지는 못합니다. 예를 들어 속성을 가상하고 재정의 할 수 있는지 알 수 없습니다. 방법을 쉽게 이해할 수 있습니다. 내 기본 클래스가 기본에있는 다른 가상 메서드를 호출해야하고 재정의 된 메서드를 호출 할 필요가 없기 때문에이 질문에 왔습니다. 기본 클래스가 기본 클래스를 다시 호출하는 재정의 된 버전을 호출했기 때문에 stackoverflow가 발생했습니다. 재정의를 새로운 것으로 바꾸면 모든 것이 잘 작동합니다. 기본 가상 메서드를 호출해야한다고 지정하는 방법이 있으면 좋겠지 만 불가능한 것처럼 보입니다. - Peter Huber

51

내면에ChildClass.methodTwo(), 전화해도됩니다base.methodTwo().

수업 외부, 전화((ParentClass)a).methodTwo()) 의지요구ChildClass.methodTwo. 이것이 가상의 방법이 존재하는 전체 이유입니다.


  • .., 그리고 남용되는 모든 방법에 대해 -1. - Michael Meadows
  • 마이클 - 다형성 행동에 대한 누군가의 설명을 떨어 뜨렸습니까? 크레이그 (Craig)는 단순히 일이 왜 그런 식으로 작동 하는지를 설명하는 것이 었습니다. 과용되는 것으로 생각되는 개념을 설명하기 만하면 좋은 답변을 하향 투표하는 것에 대해 성급하게 말하지 않았습니다. - Andrew Hare
  • 나는 그가 농담을하고 있었다고 생각한다. :) - Craig Stuntz
  • downvote하지 않았습니다. 다형성의 과용에 대해 제 1 센트를 던지고 싶었습니다. 그게 확실하지 않다면 미안 해요. - Michael Meadows

3

위에서 언급했듯이 PRODUCTION 코드에서 "base.base"를 호출해야하는 경우 클래스 디자인에 문제가 있습니다. 그러나 컴파일 할 수없는 외부 라이브러리를 사용하면서 일부 작업장을 디버깅하거나 검색하는 경우이 기술을 사용하는 것이 합법적입니다. C #이이 옵션을 직접 제공하지 않는다는 것은 좋지 않습니다. 아직도 당신은 일리노이 발전기와 Emit과 Kenneth Xu 솔루션을 사용할 수 있습니다. 그것은 작동합니다.

class A { public virtual string foo() { return "A"; } }

class B : A { public override string foo() { return "B"; } }

// now in class C
class C : B {}      
// we can call virtual method "foo" from A using following code
MethodInfo fooA = typeof(A).GetMethod("foo", BindingFlags.Public | BindingFlags.Instance);

DynamicMethod baseBaseFoo = new DynamicMethod(
            "foo_A",
            typeof(string),
            new[] { typeof(A) },
            typeof(A));
        ILGenerator il = baseBaseFoo.GetILGenerator();
        il.Emit(OpCodes.Ldarg, 0);
        il.EmitCall(OpCodes.Call, fooA, null);
        il.Emit(OpCodes.Ret);

// call foo() from class A, it returns "A"
(string)baseBaseFoo.Invoke(null, new object[] { this });

참조 용 샘플 및 전체 샘플http://kennethxu.blogspot.cz/2009/05/cnet-calling-grandparent-virtual-method.html

Kenneth Xu 감사합니다!



2

Mark Gravell이 말했듯이, 아니, 외부 적으로는 아닙니다. 하지만 여기 제가 사용한 또 다른 해킹이 있습니다.ChildClass폭로 할 수있다.methodTwo()~로부터ParentClass자체 사용 또는 외부 사용을 위해. 귀하의 경우 :

class ChildClass : ParentClass {
    override public int methodTwo() {
        return 2;
    }
    public int ParentClass_methodTwo() {
        return base.methodTwo();
    }
}

// Now instead of
Console.WriteLine("ParentClass methodTwo: " + ((ParentClass)a).methodTwo());
// use
Console.WriteLine("ParentClass methodTwo: " + a.ParentClass_methodTwo());

필자의 경우, 자식 클래스는 피어 (peer) 개념을 도입했으며,methodTwo()피어에서 기본 버전을 호출합니다. 그러나 그것을 오버라이드하여 숨겼습니다 ... 아니면 그랬습니까? 이 기술은 구조에 왔습니다.

class ChildClass : ParentClass {
    ChildClass peer;
    override public int methodTwo() {
        return peer.ParentClass_methodTwo();
    }
    private int ParentClass_methodTwo() {
        return base.methodTwo();
    }
}


2

public class Parent 
{
    public string Method()
    {
       return "parent";

    }
}

public class Child:Parent
{
    public string Method()
    {
       return "child";

    }
}

위의 코드는 부모 메서드의 값을 성공적으로 재정의하지만 여전히 부모 메서드의 값을 변경하지 않습니다.

둘 다에서 값을 반환 할 수 있습니다.학급하위 클래스아래 코드 사용 -

Child child = new Child();
string result = (((Parent)child).Method()) + child.Method();

그러나 Visual Studio는 컴파일 타임에 경고를 표시합니다.



1

내 지식으로는 일단 메소드가 오버라이드되면 부모 메소드를 호출 할 수 없다.


  • 이것은 나쁜 대답이 아닙니다. 나는 그가 당신이 질문의 정신 인 자녀의 인스턴스에서 재정의 된 부모 메서드를 호출 할 수 없다는 것을 의미했다고 생각합니다. - Andrew Hare

0

ParentClass의 인스턴스를 직접 작성하지 않으면 불가능하다고 생각합니다. 그게 바로 상속, 다형성의 본질 ...


0

나는이 도움을 찾다가 우연히 발견했고, 조상의 방법을 호출하는 방법으로 끝을 맺었다. 이는 조상 클래스를 편집 할 수 있다고 가정하는 해결 방법입니다.

상위 클래스에있는 문제의 기능을 필요한 매개 변수와 함께 정적 메서드에 넣습니다. 이 클래스의 메서드는 기능을 복제 할 필요가 없도록 호출 할 수 있으며 자식 클래스는 필요한 경우 정적 메서드를 통해 해당 기능을 호출 할 수 있습니다. 그렇게하면 메서드 내에서도 수행 할 수 있으며 호출 할 특정 클래스를 인용 할 수 있습니다. 또한, 그것은 단순한 부모보다 더 먼 선조들에 접근 할 수 있는데, 이것은 "기본"의 사용 제한이다.

연결된 질문


관련된 질문

최근 질문