2010-09-19 11 views
41

Tengo una clase base y una base de clases heredadas. La clase base tiene varias funciones virtuales que la clase heredada puede anular. Sin embargo, las funciones virtuales en la clase base tienen un código que DEBE ejecutarse antes de que se llame a las anulaciones de clases heredadas. ¿Hay alguna forma de que pueda llamar primero a las funciones virtuales de las clases base y luego anular las clases heredadas? Sin hacer una llamada a base.function().Función de base de llamadas y luego función heredada

Sé que puedo simplemente hacer dos funciones, una que es llamada, la otra virtual. Pero, ¿hay alguna manera de que pueda mantener los mismos nombres? Sé que podría necesitar cambiar algunas cosas.

class myBase 
{ 
    public virtual myFunction() 
     { /* must-run code, Called first */ } 
} 

class myInherited : myBase 
{ 
    public override myFunction() 
     { /* don't use base.myFunction();, 
     called from base.myFunction(); */ } 
} 

pregunta similares here.

Respuesta

44

Una solución común que se puede encontrar en .NET Framework es dividir un método en un método público XXX y un método virtual protegido OnXXX que es llamado por el método público. Para su ejemplo, se vería así:

class MyBase 
{ 
    public void MyMethod() 
    { 
     // do something 
     OnMyMethod(); 
     // do something 
    } 

    protected virtual void OnMyMethod() 
    { 
    } 
} 

y

class MyInherited : MyBase 
{ 
    protected override void OnMyMethod() 
    { 
     // do something 
    } 
} 
+0

¿Hay alguna manera de hacer esto sin hacer dos funciones en la clase base?o al menos hacer que tengan el mismo nombre? – Dave

+3

@Dave: No, no hay forma de llamar mágicamente a un método base anulado antes o después de la llamada al método virtual. Tienes que dividirlo de alguna manera. (Si lo divide, también puede exigir que un método de anulación invoque el método base anulado, además de hacer algo antes y después del método protegido). – dtb

+3

También conocido como idioma de interfaz no virtual - http: // en. wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface – sll

60

C# no tiene soporte para hacer cumplir de forma automática, pero se puede cumplir mediante el uso de la template method pattern. Por ejemplo, imagina que tenía este código:

abstract class Animal 
{ 
    public virtual void Speak() 
    { 
     Console.WriteLine("I'm an animal."); 
    } 
} 

class Dog : Animal 
{ 
    public override void Speak() 
    { 
     base.Speak(); 
     Console.WriteLine("I'm a dog."); 
    } 
} 

El problema aquí es que cualquier clase que hereda de Animal tiene que llamar base.Speak(); para asegurar que se ejecuta el comportamiento de la base. Puede aplicar automáticamente esta tomando el enfoque siguiente (ligeramente diferente):

abstract class Animal 
{ 
    public void Speak() 
    { 
     Console.WriteLine("I'm an animal."); 
     DoSpeak(); 
    } 

    protected abstract void DoSpeak(); 
} 

class Dog : Animal 
{ 
    protected override void DoSpeak() 
    { 
     Console.WriteLine("I'm a dog."); 
    } 
} 

En este caso, los clientes todavía sólo ver el método polimórfico Speak, pero el comportamiento Animal.Speak está garantizado para ejecutar. El problema es que si tiene más herencia (por ejemplo, class Dachshund : Dog), tiene que crear otro método abstracto si desea que se ejecute Dog.Speak.

0

No hay forma de hacer lo que está buscando, excepto las 2 formas que ya mencionó.

O se hacen 2 funciones en la clase base, uno que es llamada y la otra virtual.

O llama a base.functionName en la subclase.

0

No exactamente. Pero he hecho algo similar usando métodos abstractos.

Los métodos abstractos deben ser modificados por las clases derivadas. Los procs abstractos son virtuales, por lo que puede estar seguro de que cuando la clase base los llama, se llama a la versión de la clase derivada. Luego haga que el "Código de ejecución obligatoria" de su clase base llame al proceso abstracto después de ejecutar. voila, el código de su clase base siempre se ejecuta primero (asegúrese de que el proc de la clase base ya no sea virtual) seguido del código de su clase derivada.

class myBase 
{ 
    public /* virtual */ myFunction() // remove virtual as we always want base class's function called here 
    { /* must-run code, Called first */ 

     // call derived object's code 
     myDerivedMustcallFunction();  
    } 

    public abstract myDerivedMustCallFunction() { /* abstract functions are blank */ } 
} 

class myInherited : myBase 
{ 
    public override myDerivedMustCallFunction() 
    { /* code to be run in derived class here */ } 
} 
+1

¿Por qué es público el método abstracto? – Casey

0

¿Qué opinas de esto?

class myBase 
{ 
    public void myFunctionWrapper() 
    { 
     // do stuff that must happen first 
     // then call overridden function 
     this.myFunction(); 
    } 

    public virtual void myFunction(){ 
     // default implementation that can be overriden 

    } 

} 

class myInherited : myBase 
{ 
    public override void myFunction() 
    { 

    } 
} 
Cuestiones relacionadas