web-dev-qa-db-fra.com

Est-il possible d'appeler la version parente d'une méthode substituée? (C # .NET)

Dans le code ci-dessous, j'ai essayé de deux manières d'accéder à la version parente de methodTwo, mais le résultat était toujours 2. Existe-t-il un moyen d'obtenir le résultat 1 d'une instance de ChildClass sans modifier ces deux classes?

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();
    }
}

Mise à jour ChrisW a posté ceci:

En dehors de la classe, je ne sais pas tout moyen facile; mais peut-être que non savoir ce qui se passe si vous essayez réflexion: utilisez la méthode Type.GetMethod méthode pour trouver le MethodInfo associé à la méthode dans le ParentClass, puis appelez MethodInfo.Invoke

Cette réponse a été supprimée. Je me demande si ce bidouillage pourrait fonctionner, juste par curiosité.

32
Jader Dias

Au niveau IL, vous pouvez probablement émettre un call plutôt qu'un callvirt et faire le travail - mais si nous nous limitons à C # ;-p ( edit darn! Le runtime vous arrête: VerificationException: "Operation pourrait déstabiliser le temps d’exécution. "; supprimez la virtual et cela fonctionne très bien; trop intelligent de moitié ...)

Dans le type ChildClass, vous pouvez utiliser base.methodTwo() - toutefois, cela n'est pas possible en externe. Vous ne pouvez pas non plus descendre plus d'un niveau - il n'y a pas de support base.base.Foo().

Cependant, si vous désactivez le polymorphisme en utilisant la méthode-Hiding, vous pouvez obtenir le answer vous voulez, mais pour de mauvaises raisons:

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

Vous pouvez maintenant obtenir une réponse différente à partir du même objet, selon que la variable est définie comme étant une variable ChildClass ou une variable ParentClass.

35
Marc Gravell

Dans ChildClass.methodTwo(), vous pouvez appeler base.methodTwo().

En dehors de la classe, appelez ((ParentClass)a).methodTwo()) will call ChildClass.methodTwo. C'est la raison pour laquelle les méthodes virtuelles existent. 

53
Craig Stuntz

Comme mentionné ci-dessus, la conception de votre classe présente un problème si vous devez appeler "base.base" dans le code PRODUCTION. Mais il est tout à fait légitime d’utiliser cette technique si vous déboguez ou recherchez des solutions de contournement tout en utilisant des bibliothèques externes que vous ne pouvez pas compiler. Il est désagréable que C # ne fournisse pas cette option directement. Vous pouvez toujours utiliser la solution Kenneth Xu avec le générateur IL et Emit. Ça marche.

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 });

Pour un exemple et un exemple complet, voir http://kennethxu.blogspot.cz/2009/05/cnet-calling-grandparent-virtual-method.html

Merci Kenneth Xu!

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

    }
}

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

    }
}

Le code ci-dessus remplace avec succès la méthode parente mais la valeur de la méthode parente reste inchangée. 

Vous pouvez retourner des valeurs à partir de Both Parent class et Child class en utilisant le code ci-dessous - 

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

Mais Visual Studio vous montrera un avertissement dans Compile Time. 

2
HammrerEngineer

Comme Mark Gravell l'a dit, non, pas à l'extérieur. Mais voici un autre hack que j'ai utilisé. ChildClass peut exposer methodTwo() à partir de ParentClass pour son propre usage ou pour un usage externe. Dans ton cas:

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());

Dans mon cas, la classe enfant a introduit le concept d'homologue et j'ai besoin de sa substitution de methodTwo() pour appeler la version de base de l'homologue. En le déroutant, cependant, il l'a caché ... Ou l'a-t-il fait? Cette technique est venue à la rescousse.

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

À ma connaissance, une fois qu'une méthode a été remplacée, vous ne pouvez pas appeler la méthode parente.

1
Vince Panuccio

Je suis tombé sur cette recherche d'aide et je me suis retrouvé avec ma propre approche d'appeler les versions ancêtres d'une méthode. Il s’agit plus d’une solution de contournement qui suppose que vous puissiez éditer la classe ancêtre:

Placez la fonctionnalité en question dans la classe ancêtre dans une méthode statique, avec les paramètres nécessaires. La méthode de cette classe peut l'appeler pour éviter la duplication de la fonctionnalité. La classe enfant peut également appeler cette fonctionnalité via la méthode statique. De cette façon, cela peut être fait même dans une méthode et peut citer quelle classe spécifique il veut invoquer. En outre, il peut accéder à des ancêtres plus lointains que de simples parents, ce qui est la limitation de l'utilisation "base".

0
user3208955

Je pense que ce n’est possible que si vous créez directement une instance de ParentClass ... C’est l’essentiel de l’héritage, du polymorphisme ...

0
Julius A