Подтвердить что ты не робот

Есть ли способ вызвать родительскую версию переопределенного метода? (С#.NET)

В приведенном ниже коде я попытался двумя способами получить доступ к родительской версии метода 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

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

Ответ 3

Как упоминалось выше, что-то плохое в дизайне вашего класса, если вам нужно вызвать "base.base" в коде ПРОДУКЦИИ. Но вполне логично использовать эту технику, если вы отлаживаете или выполняете поиск по некоторым рабочим параметрам при использовании внешних библиотек, которые невозможно скомпилировать. Неприятно, что С# не предоставляет эту опцию напрямую. Тем не менее вы можете использовать решение 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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

    }
}

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

    }
}

Выше кода успешно переопределяет родительский метод, но значение родительского метода все равно остается неизменным.

Вы можете возвращать значения из класса Родительский класс и Child с использованием кода ниже -

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

Но Visual Studio покажет вам предупреждение во время компиляции.

Ответ 7

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

Ответ 8

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

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