2010-10-20 11 views
18

¿Existe una construcción en Java o C# que obligue a las clases heredadas a llamar a la implementación base? Puede llamar a super() o base(), pero ¿es posible hacer que arroje un error en tiempo de compilación si no se llama? Eso sería muy conveniente ..Método de base de fuerza llamada

--edit--

Soy curioso sobre todo anulando métodos.

+0

¿Quieres decir desde un constructor de cuándo sustituir un método? – munificent

Respuesta

12

No hay ni debe haber nada que haga eso.

Lo más parecido que se me ocurre de la mano fuera si algo como tener esto en la clase base:

public virtual void BeforeFoo(){} 

public void Foo() 
{ 

this.BeforeFoo(); 
//do some stuff 
this.AfterFoo(); 

} 

public virtual void AfterFoo(){} 

y permitir que la anulación de la clase que hereda BeforeFoo y/o AfterFoo

+5

Lo que sugirió parece ser la solución común al problema. Aunque tenerlo forzar (o llamarlo automáticamente) la clase heredada para llamarlo sería conveniente y haría que ciertos errores sean fáciles de encontrar. ¿Podría explicar en detalle por qué * no debería haber * ninguna característica? Va en contra de los conceptos básicos de polimorfismo y si lo hace, ¿por qué? – irwinb

+0

Si tengo una clase que amplía otra clase que me obliga a llamar a base.Foo() en algún lugar de mi Foo, eso es bastante limitante. Llamo a base.Foo() si quiero esa funcionalidad, o no puedo usar la clase para ampliar la mía. El compilador debe hacer cumplir un conjunto mínimo de reglas básicas. Debería verificar los contratos de código para .NET http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx – MStodd

0

No creo que haya ninguna solución factible incorporada. Sin embargo, estoy seguro de que hay herramientas de análisis de código separadas que pueden hacer eso.

0

EDIT Interpretar mal la construcción como constructor. Dejando como CW ya que se ajusta a un subconjunto muy limitado del problema.

En C# puede forzar este comportamiento definiendo un único constructor que tenga al menos un parámetro en el tipo de base. Esto elimina el constructor predeterminado y obliga a los tipos derivados a llamar explícitamente a la base especificada o reciben un error de compilación.

class Parent { 
    protected Parent(int id) { 
    } 
} 

class Child : Parent { 
    // Does not compile 
    public Child() {} 
    // Also does not compile 
    public Child(int id) { } 
    // Compiles 
    public Child() :base(42) {} 

} 
+0

Creo que esto también funciona en Java. – BoltClock

+0

Creo que OP está hablando de ser capaz de forzar 'anulación pública void Method() {base.Method(); ...} ', no sobre constructores. – Ani

+0

Esto solo funciona para constructores, sin embargo. –

6

No en Java. Podría ser posible en C#, pero alguien más tendrá que hablar de eso.

Si he entendido bien desea que esta:

class A { 
    public void foo() { 
     // Do superclass stuff 
    } 
} 

class B extends A { 
    public void foo() { 
     super.foo(); 
     // Do subclass stuff 
    } 
} 

Lo que puede hacer en Java para hacer cumplir el uso del foo superclase es algo así como:

class A { 
    public final void foo() { 
     // Do stuff 
     ... 
     // Then delegate to subclass 
     fooImpl(); 
    } 

    protected abstract void fooImpl(); 
} 

class B extends A { 
    protected void fooImpl() { 
     // Do subclass stuff 
    } 
} 

Es feo, pero logra lo usted quiere. De lo contrario, solo tendrá que tener cuidado para asegurarse de llamar al método de la superclase.

Tal vez podría jugar con su diseño para solucionar el problema, en lugar de utilizar una solución técnica. Puede que no sea posible, pero probablemente valga la pena pensar en ello.

EDIT: Quizás he entendido mal la pregunta. ¿Estás hablando solo de constructores o métodos en general? Supuse métodos en general.

+1

+1: No creo que sea feo. Es el patrón de método de plantilla y el enfoque adecuado. El nombre fooImpl() es feo, pero esto es solo un ejemplo ... –

0

en Java, el compilador solo puede hacer cumplir esto en el caso de los constructores.

Un constructor debe llamarse hasta la cadena de herencia ... es decir, si Dog extiende Animal extends Thing, el constructor de Dog debe llamar a un constructor para Animal debe llamar a un constructor para Thing.

Este no es el caso para los métodos regulares, donde el programador debe llamar explícitamente una implementación súper si es necesario.

La única manera de hacer cumplir un código implementación base para ser ejecutado es dividir código de anulación-poder en una llamada de método separado:

public class Super 
{ 
    public final void doIt() 
    { 
    // cannot be overridden 
     doItSub(); 
    } 

    protected void doItSub() 
    { 
    // override this 
    } 
} 

public class Sub extends Super 
{ 
    protected void doItSub() 
    { 
    // override logic 
    } 
} 
2

Si he entendido bien desea exigir que el comportamiento de la clase base es no anulado, pero aún así poder extenderlo, entonces usaría el patrón de diseño del método de la plantilla y en C# no incluiría la palabra clave virtual en la definición del método.

1

No. No es posible. Si usted tiene que tener una función que hace algo antes o después de la acción de hacer algo como esto:

internal class Class1 
{ 
    internal virtual void SomeFunc() 
    { 
     // no guarantee this code will run 
    } 


    internal void MakeSureICanDoSomething() 
    { 
     // do pre stuff I have to do 

     ThisCodeMayNotRun(); 

     // do post stuff I have to do 
    } 

    internal virtual void ThisCodeMayNotRun() 
    { 
     // this code may or may not run depending on 
     // the derived class 
    } 
} 
0

me encontré a este post y no necesariamente me gustó ninguna respuesta en particular, así que pensé que proporcionaría la mía ...

No hay forma en que C# haga cumplir que se llama al método base. Por lo tanto, la codificación como tal se considera un antipatrón debido a que un desarrollador de seguimiento puede no darse cuenta de que debe llamar al método base, de lo contrario la clase estará en un estado incompleto o incorrecto.

Sin embargo, he encontrado circunstancias en las que se requiere este tipo de funcionalidad y se pueden cumplir en consecuencia. Por lo general, la clase derivada necesita un recurso de la clase base. Para obtener el recurso, que normalmente podría estar expuesto a través de una propiedad, se expone a través de un método. La clase derivada no tiene más remedio que llamar al método para obtener el recurso, por lo que se asegura de que se ejecute el método de la clase base.

La siguiente pregunta lógica que uno podría hacerse es ¿por qué no ponerla en el constructor? La razón es que puede tratarse de un problema de orden de operaciones. En el momento en que se construye la clase, pueden faltar algunas entradas.

¿Esto se aleja de la pregunta? Si y no. Sí, obliga a la clase derivada a llamar a un método de clase base particular. No, no hace esto con la palabra clave override. ¿Podría ser útil para una persona que busca una respuesta a esta publicación, tal vez?

No estoy predicando esto como un evangelio, y si las personas ven una desventaja de este enfoque, me encantaría saberlo.

1

No he leído TODAS las respuestas aquí; sin embargo, estaba considerando la misma pregunta. Después de revisar lo que REALMENTE quería hacer, me pareció que si quería FORZAR la llamada al método base, no debería haber declarado el método base virtual (anulable) en primer lugar.

2

El siguiente ejemplo arroja un InvalidOperationException cuando la funcionalidad base no se hereda al anular un método.

Esto podría ser útil para situaciones en las que el API interno invoca el método.

i.e.donde Foo() no está diseñado para ser invocado directamente:

public abstract class ExampleBase { 
    private bool _baseInvoked; 

    internal protected virtual void Foo() { 
     _baseInvoked = true; 
     // IMPORTANT: This must always be executed! 
    } 

    internal void InvokeFoo() { 
     Foo(); 
     if (!_baseInvoked) 
      throw new InvalidOperationException("Custom classes must invoke `base.Foo()` when method is overridden."); 
    } 
} 

Obras:

public class ExampleA : ExampleBase { 
    protected override void Foo() { 
     base.Foo(); 
    } 
} 

grita:

public class ExampleB : ExampleBase { 
    protected override void Foo() { 
    } 
} 
Cuestiones relacionadas