Есть ли способ вызвать родительскую версию переопределенного метода? (C # .NET) - PullRequest
35 голосов
/ 13 января 2009

В приведенном ниже коде я пытался двумя способами получить доступ к родительской версии methodTwo, но результат всегда был равен 2. Есть ли способ получить результат 1 из экземпляра ChildClass без изменения этих двух классов?

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 это опубликовал:

Из-за пределов класса я не знаю любой простой способ; но, возможно, я не знать, что произойдет, если вы попробуете отражение: используйте Type.GetMethod метод, чтобы найти MethodInfo связано с методом в ParentClass, а затем вызвать MethodInfo.Invoke

Этот ответ был удален. Мне интересно, может ли этот хак сработать, просто ради любопытства.

Ответы [ 8 ]

54 голосов
/ 13 января 2009

Внутри ChildClass.methodTwo() вы можете позвонить base.methodTwo().

Вне класса звонки ((ParentClass)a).methodTwo()) будут звонить ChildClass.methodTwo. Вот и вся причина существования виртуальных методов.

37 голосов
/ 13 января 2009

На уровне IL вы, вероятно, могли бы выдать call вместо callvirt и выполнить работу - но если мы ограничимся C # ;-p ( edit darn! The время выполнения останавливает вас: VerificationException: «Операция может дестабилизировать время выполнения.»; удалите virtual, и он работает нормально; слишком умный наполовину ...)

Внутри типа ChildClass вы можете использовать base.methodTwo() - однако внешне это невозможно. Вы также не можете пройти более одного уровня - поддержка base.base.Foo() отсутствует.

Однако, если вы отключите полиморфизм, используя скрытие методов, вы можете получить ответ , который вы хотите, но по плохим причинам:

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

Теперь вы можете получить разные ответы от одного и того же объекта в зависимости от того, определена ли переменная как ChildClass или ParentClass.

4 голосов
/ 02 сентября 2015

Как уже упоминалось выше, что-то плохое в дизайне вашего класса, если вам нужно вызвать "base.base" в коде PRODUCTION. Но вполне законно использовать эту технику, если вы отлаживаете или ищете какие-то временные решения, используя внешние библиотеки, которые не можете скомпилировать. Неприятно, что C # не предоставляет эту опцию напрямую. Тем не менее, вы можете использовать решение Kenneth Xu с генератором IL и Emit. Это работает.

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

Спасибо, Кеннет Сюй!

2 голосов
/ 17 июня 2016
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 покажет вам предупреждение во время компиляции.

2 голосов
/ 19 февраля 2013

Как сказал Марк Гравелл, нет, не внешне. Но вот еще один взлом, который я использовал. 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();
    }
}
1 голос
/ 13 января 2009

Насколько мне известно, после переопределения метода нельзя вызвать родительский метод.

0 голосов
/ 18 января 2014

Я наткнулся на это в поисках помощи и закончил с моим собственным подходом к вызову версий метода-предка. Это больше обходной путь, который предполагает, что вы можете редактировать класс предка:

Поместите рассматриваемую функциональность в классе предка в статический метод с необходимыми параметрами. Метод в этом классе может вызывать его, поэтому ему не нужно дублировать функциональность, и дочерний класс может вызывать эту функциональность при желании через статический метод. Таким образом, это может быть сделано даже внутри метода и может указывать, какой конкретный класс он хочет вызвать. Кроме того, он может получить доступ к более дальним предкам, чем простые родители, что является ограничением использования «базы».

0 голосов
/ 13 января 2009

Я думаю, что это невозможно, если вы не создадите экземпляр ParentClass напрямую. Вот суть наследства, полиморфизм ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...