web-dev-qa-db-fra.com

Comment puis-je appeler «l'implémentation de base» d'une méthode virtuelle surchargée?

Étant donné le code suivant, existe-t-il un moyen d'appeler la version de classe A de la méthode 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...
  }
67
mackenir

En utilisant les constructions de langage C #, vous ne pouvez pas appeler explicitement la fonction de base depuis en dehors de la portée de A ou B. Si vous avez vraiment besoin de le faire, il y a un défaut dans votre conception - c'est-à-dire que cette fonction ne doit pas être virtuelle au départ, ou qu'une partie de la fonction de base doit être extraite vers une fonction non virtuelle distincte.

Vous pouvez de à l'intérieur B.X mais appelez A.X

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

Mais c'est autre chose.

Comme le souligne Sasha Truf dans cette réponse , vous pouvez le faire via IL. Vous pouvez probablement aussi l'accomplir par la réflexion, comme le souligne mhand dans les commentaires.

107
Pete

Vous ne pouvez pas le faire en C #, mais vous pouvez modifier MSIL.

Code IL de votre méthode Main:

.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 
}

Vous devez changer l'opcode dans L_0008 de callvirt à call

L_0008: call instance void MsilEditing.A::X()
13
Sasha Truf

Vous pouvez le faire, mais pas au point que vous avez spécifié. Dans le contexte de B, vous pouvez appeler A.X() en appelant base.X().

9
John Feminella

Vous ne pouvez pas, et vous ne devriez pas. C'est à cela que sert le polymorphisme, de sorte que chaque objet a sa propre façon de faire des choses "de base".

8
Jorge Córdoba

Je ne connais pas sa question d'histoire. Mais pour les autres googleurs: vous pourriez écrire quelque chose comme ça. Mais cela nécessite un changement de classe de base ce qui la rend inutile avec les bibliothèques externes.

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


  }
4
lkuder

C'est impossible si la méthode est déclarée dans la classe dérivée comme overrides. pour ce faire, la méthode de la classe dérivée doit être déclarée comme 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

Voir violon ici

2
Zohar Peled