2010-10-20 3 views
18

Esiste un costrutto in Java o C# che impone alle classi ereditarie di chiamare l'implementazione di base? Puoi chiamare super() o base() ma è possibile farlo lanciare un errore in fase di compilazione se non viene chiamato? Sarebbe molto comodo ..Chiamata metodo base forza

--edit--

Sono soprattutto curioso di override metodi.

+0

Vuoi dire da un costruttore di quando l'override un metodo? – munificent

risposta

12

Non c'è e non dovrebbe esserci nulla per farlo.

La cosa più vicina che posso pensare fuori mano se qualcosa di simile avere questo nella classe base:

public virtual void BeforeFoo(){} 

public void Foo() 
{ 

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

} 

public virtual void AfterFoo(){} 

e consentire la classe eredita di override BeforeFoo e/o AfterFoo

+5

Quello che hai suggerito sembra essere la soluzione comune al problema. Anche se averlo forzato (o chiamarlo automaticamente) la classe ereditaria per chiamarlo sarebbe conveniente e renderebbe facile trovare certi errori. Potresti approfondire il motivo per cui * non dovrebbe * esserci alcuna caratteristica? Va contro i concetti di polimorfismo di base e se lo fa, perché? – irwinb

+0

Se ho una classe che estende un'altra classe che mi costringe a chiamare base.Foo() da qualche parte nel mio Foo, è piuttosto limitante. O chiamare base.Foo() se voglio quella funzionalità, o non posso usare la classe per estendere il mio. Il compilatore dovrebbe applicare una serie minima di regole di base. Dovresti controllare i contratti di codice per .NET http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx – MStodd

0

Non pensare che ci sia una soluzione fattibile integrata. Sono sicuro che ci sono strumenti di analisi del codice separati che possono farlo, però.

0

EDIT Costruzione errata come costruttore. Lasciando come CW poiché si adatta a un sottoinsieme molto limitato del problema.

In C# è possibile forzare questo comportamento definendo un singolo costruttore con almeno un parametro nel tipo base. Questo rimuove il costruttore predefinito e forza i tipi derivati ​​a chiamare esplicitamente la base specificata o ottengono un errore di compilazione.

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

Credo che funzioni anche in Java. – BoltClock

+0

Penso che l'OP stia parlando di poter forzare 'public override void Method() {base.Method(); ...} ', non sui costruttori. – Ani

+0

Questo funziona solo per i costruttori, però. –

6

Non in Java. Potrebbe essere possibile in C#, ma qualcun altro dovrà parlarne.

Se ho capito bene si desidera che questo:

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

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

Cosa si può fare in Java per imporre l'utilizzo del foo superclasse è qualcosa di simile:

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

E 'brutto, ma realizza ciò che tu vuoi. Altrimenti dovrai solo fare attenzione a chiamare il metodo della superclasse.

Forse potresti armeggiare con il tuo progetto per risolvere il problema, piuttosto che usare una soluzione tecnica. Potrebbe non essere possibile, ma probabilmente vale la pena pensarci.

EDIT: Forse ho frainteso la domanda. Stai parlando solo di costruttori o metodi in generale? Ho assunto metodi in generale.

+1

+1: non penso che sia brutto. È il modello di metodo del modello e l'approccio corretto. Il nome fooImpl() è brutto, ma questo è solo un esempio ... –

0

in Java, il compilatore può solo far rispettare questo nel caso di Costruttori.

Un costruttore deve essere chiamato fino alla catena di ereditarietà. Ad esempio, se Dog estende Animal estende Thing, il costruttore per Cane deve chiamare un costruttore per Animal deve chiamare un costruttore per Cosa.

Questo non è il caso dei metodi regolari, in cui il programmatore deve chiamare esplicitamente una super implementazione, se necessario.

L'unico modo per far rispettare un codice implementazione di base da eseguire è quella di dividere il codice override-in grado in un metodo chiamata separata:

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

Se ho capito bene si desidera imporre che il vostro comportamento classe base è non sovrascritto, ma ancora in grado di estenderlo, quindi vorrei utilizzare il modello di modello di progettazione del modello e in C# non includere la parola chiave virtuale nella definizione del metodo.

1

No. Non è possibile. Se si deve avere una funzione che fa una certa azione pre o post fare qualcosa di simile:

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

mi sono imbattuto su questo post e non mi è piaciuta nessuna risposta particolare, quindi ho pensato di fornire il mio ...

Non c'è modo in C# per far rispettare il metodo di base. Pertanto la codifica come tale è considerata un anti-pattern dal momento che uno sviluppatore di follow-up potrebbe non rendersi conto che devono chiamare il metodo base altrimenti la classe sarà in uno stato incompleto o cattivo.

Tuttavia, ho trovato circostanze in cui questo tipo di funzionalità è richiesto e può essere soddisfatto di conseguenza. Di solito la classe derivata ha bisogno di una risorsa della classe base. Al fine di ottenere la risorsa, che normalmente potrebbe essere esposta tramite una proprietà, viene invece esposta tramite un metodo. La classe derivata non ha altra scelta che chiamare il metodo per ottenere la risorsa, garantendo quindi che venga eseguito il metodo della classe base.

La prossima domanda logica che si potrebbe chiedere è perché non inserirla nel costruttore? Il motivo è che potrebbe trattarsi di un problema di ordine operativo. Al momento della costruzione della classe, potrebbero esserci ancora degli input mancanti.

Questo si allontana dalla domanda? Sì e no. Sì, forza la classe derivata a chiamare un particolare metodo di classe base. No, non lo fa con la parola chiave override. Potrebbe essere utile per un individuo in cerca di una risposta a questo post, forse.

Non sto predicando questo come Vangelo, e se le persone vedono un aspetto negativo di questo approccio, mi piacerebbe sentirne parlare.

1

Non ho letto TUTTE le risposte qui; tuttavia, stavo considerando la stessa domanda. Dopo aver esaminato ciò che volevo REALMENTE fare, mi è sembrato che se volessi forzare la chiamata al metodo base, non avrei dovuto dichiarare il metodo di base virtuale (override-able) in primo luogo.

2

L'esempio seguente genera un InvalidOperationException quando la funzionalità di base non viene ereditata quando si esegue l'override di un metodo.

Questo potrebbe essere utile per scenari in cui il metodo è invocato da alcune API interne.

, ad es.dove Foo() non è progettato per essere invocato direttamente:

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."); 
    } 
} 

Works:

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

urla:

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