2011-07-22 13 views
7

¿Hay alguna manera de agregar una función virtual que todas las clases heredadas deben anular? Entonces, ¿la combinación de lo virtual y lo abstracto? Tengo una situación en la que cada clase heredada debe realizar un procesamiento específico antes de que se ejecute algún código genérico. Las funciones virtuales no funcionan porque no aseguran que las clases heredadas las anulen. Y la función abstracta no puede tener una implementación predeterminada. Actualmente mi solución alternativa es implementar otra función protegida en la clase base que contiene el código común/genérico y se llama en la función abstracta omitidaC# Función abstracta con implementación posible?

+6

Si tiene una implementación predeterminada ¿por qué NECESITA ser anulada? ¿Eso no derrota el propósito? ¿Por qué no simplemente hacerlo abstracto si siempre va a ser anulado? –

+0

Cuando anula la función, simplemente puede cambiar el cuerpo. no puedes cambiar la firma del método – Peyman

Respuesta

10

No es posible tener un método que sea abstracto y virtual.

Si es posible, se puede dividir su método en un "antes" y "después" de parte:

public void DoWork() 
{ 
    DoBeforeWork(); 
    DoCommonWork(); 
    DoAfterWork(); 
} 

protected abstract void DoBeforeWork(); 
protected abstract void DoAfterWork(); 

private void DoCommonWork() { ... } 

lo contrario, su solución con un segundo método protegido es una muy buena idea:

public void DoWork() 
{ 
    DoActualWork(); 
} 

protected abstract void DoActualWork(); // expected to call DoCommonWork 

protected void DoCommonWork() { ... } 

Puede verificar si DoCommonWork realmente fue llamado en DoWork usando un campo local de subprocesos si es necesario.

Sin embargo, probablemente sea mejor que el método sea virtual. Si la clase derivada no quiere añadir nada a la parte común, no debería tener que:

public virtual void DoWork() { ... } 

Una vez más, se puede comprobar si la parte común se llama realmente.

+0

+1 para su primer ejemplo, aunque estuvo casi tentado de ir -1 por el segundo porque es increíblemente peligroso y tan inseguro como el problema original. En lugar de tener que recordar anular una función virtual, ahora debemos recordar llamar a DoCommonWork desde la función abstracta. Su primer ejemplo mitiga cualquiera de este riesgo. – Will

+0

Creo que voy por su primera sugerencia.Esta construcción es segura ya que se garantiza que se llamará al código común y la función abstracta DoBeforeWork debe implementarse en las clases derivadas. – Tin

2

Creo que podría estar buscando un template method: Implemente un método en su clase base que llame a un método abstracto como parte de su implementación. Las clases derivadas pueden implementar el método abstracto, pero esto permite que la clase base haga "algún procesamiento específico" antes de que se ejecute este método.

+0

; Esta solución funciona bien para el postprocesamiento (primer código común que el código específico de clase derivada) pero necesito lo contrario: primero el código específico de la clase derivada seguido de código genérico. – Tin

0

Mi sugerencia es dividir la clase base en dos: clases una abstracta y una concreta sellada.

Ejemplo

que se supone que tiene clase base que se parece a lo siguiente:

public class BaseClass 
{ 
    public void DoProcessing() 
    { 
     // this method must be overriden in each subclass 
    } 
} 

Vamos a dividir a dos:

public abstract class BaseClass 
{ 
    protected abstract DoProcessingImlementation();  

    public void DoProcessing() 
    { 
     // here you can add program logic or just call overridden implementation 
     DoProcessingImplementation(); 
    } 
} 

public sealed class DefaultBaseClassImplementation : BaseClass 
{ 
    public override DoProcessingImlementation() 
    { 
     // default implementation of method 
    } 
} 

Con este diseño si es necesario implementar nuevas lógica de procesamiento, usted hereda la nueva clase del BaseClass y porque es abstracto debe implementar el método DoSomethigImplementation. Para acceder a la lógica de procesamiento predeterminada, debe usar una instancia de la clase DefaultBaseClassImplementation. Y que el DefaultBaseClassImplementation está sellado no le permitirá heredar de la clase incorrecta.

Cuestiones relacionadas