2010-06-30 13 views
31

Cada vez que anulo un método de una clase base, que no sea la implementación de este método, parece que tengo 3 opciones.¿Cómo "anular" correctamente un método de clase base?

1) Llame a base.Method(), y luego proporcione mi implementación.

2) Proporcionar mi aplicación y luego llamar base.Method()

3) acaba de proporcionar mi aplicación.

Recientemente, al utilizar una biblioteca, me he dado cuenta de algunos errores que se introdujeron debido a que no se implementó el método como esperaba la biblioteca. No estoy seguro de si eso es malo en parte de la biblioteca, o algo está mal en mi comprensión.

Voy a tomar un ejemplo.

public class ViewManager { 
    public virtual void Customize(){ 
     PrepareBaseView(); 
    } 
} 

public class PostViewManager { 
    public override void Customize(){ 
     base.Customize(); 
     PreparePostView(); 
    } 
} 


public class PreViewManager { 
    public override void Customize(){ 
     PreparePreView(); 
     base.Customize(); 
    } 
} 


public class CustomViewManager { 
    public override void Customize(){ 
     PrepareCustomView(); 
    } 
} 

Mi pregunta aquí es que ¿cómo podría un know clase hija (sin echar un vistazo a la implementación de la clase base) qué orden (u opción) está siendo esperado por la clase padre? ¿Hay alguna manera en la que la clase principal podría imponer una de las tres alternativas a todas las clases derivadas?

+1

'PostViewManager',' PreViewManager', 'CustomViewManager' heredan de' ViewManager'? Si es así, debe editar el código. – LaTeX

Respuesta

36

¿cómo podría saber una clase secundaria (sin tener en cuenta la implementación de la clase base) qué orden (o opción) se espera de la clase principal?

No hay forma de "saber" esto cuando se subclasan y anulan un método. La documentación adecuada es realmente la única opción aquí.

¿Hay alguna manera en que la clase principal podría imponer una de las tres alternativas a todas las clases derivadas?

La única opción aquí es evitar el problema. En lugar de permitir que la subclase anule el método, puede declararse no virtual y llamar a un método virtual en el lugar apropiado.Por ejemplo, si desea exigir que las subclases "Llame a su primera versión", que podría hacer:

public class BaseClass { 
    public void Method() // Non-virtual 
    { 
      // Do required work 

      // Call virtual method now... 
      this.OnMethod(); 
    } 

    protected virtual void OnMethod() 
    { // Do nothing 
    } 
} 

Las subclases pueden luego "anular" OnMethod, y proporcionar la funcionalidad que sucede después de 's de trabajo "método".

La razón por la que esto es obligatorio es que los métodos virtuales están diseñados para permitir que una subclase reemplace completamente la implementación de la clase principal. Esto se hace a propósito. Si desea evitar esto, es mejor que el método no sea virtual.

+1

Me ganaste. Este es el problema ** clase base frágil **. +1 para la solución (que también me ganaste :), el ** patrón de método de plantilla **. Incluso podría hacer el resumen 'OnMethod' protegido para que las clases derivadas sepan que * tienen * para proporcionar su propia implementación y, además, que no tienen que llamar a una implementación base (suponiendo que no tiene sentido crear una instancia 'Base'). – shambulator

+0

+1 Esto lo salvará del alboroto de sus compañeros desarrolladores. – Marc

+0

@shambulator - La anulación es opcional, por lo que probablemente no sea comparable hacer que 'OnMethod' sea abstracto. Todavía es una buena opción, aunque su ejemplo –

1

La respuesta corta es no. No se puede imponer en qué orden el niño llama al método base, o si lo llama en absoluto.

Técnicamente, esta información debería incluirse en la documentación del objeto base. Si absolutamente debe ejecutar algún código antes o después del código de la clase secundaria, puede hacer lo siguiente:

1) Crear una función no virtual en la clase base. Llamémoslo MiFunción

2) Cree una función virtual protegida en la clase base. Llamémoslo _MyFunction

3) Las clases derivadas extienden el método _MyFunction.

4) Haga que MyFunction llame a _MyFunction y ejecute el código que necesita para ejecutar antes o después de llamarlo.

Este método es feo y requeriría una gran cantidad de código adicional, por lo que recomendamos simplemente poner un aviso en la documentación.

+0

Me pregunto si algo como PostSharp podría hacer cumplir ese pedido. – FrustratedWithFormsDesigner

0

Los requisitos de la clase base deben ser documentados por el diseñador de la biblioteca. Este es el motivo por el que algunas bibliotecas contienen principalmente clases selladas.

2

Es por eso que creo que los métodos virtuales son peligrosos cuando los envía a una biblioteca. La verdad es que nunca se sabe realmente sin mirar la clase base, a veces hay que disparar reflektor, leer la documentación o abordarla con prueba y error.

Al escribir código yo siempre he cansado para seguir la regla que dice:

Las clases derivadas que anulan el método virtual protegida no están obligados a llamar a la implementación de la clase base. La clase base debe continuar funcionando correctamente incluso si no se llama a su implementación.

Esto está tomado de http://msdn.microsoft.com/en-us/library/ms229011.aspx, sin embargo, esto es para el diseño de eventos, aunque creo que he leído esto en el libro de directrices de diseño de Framework (http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756).

Sin embargo, esto obviamente no es cierto, los formularios web ASP.NET, por ejemplo, requieren una llamada base en Page_Load.

Por lo tanto, de largo y corto, varía y, lamentablemente, no hay forma de saberlo al instante. Si tengo dudas, omitiré la llamada inicialmente.

+0

¡Qué maravillosa respuesta! Mis pensamientos exactos. Hasta votado. – Xtro

Cuestiones relacionadas