2012-03-28 14 views
12

Come impedire che un metodo venga sovrascritto in una classe derivata?Impedire la sovrascrittura di un metodo in C#

In Java, è possibile farlo utilizzando il modificatore final sul metodo che si desidera evitare di sovrascrivere.

Come ottengo lo stesso risultato in C#?
Sono a conoscenza dell'uso di sealed ma a quanto pare posso usarlo solo con la parola chiave override?

class A 
{ 
    public void methodA() 
    { 
     // Code. 
    } 

    public virtual void methodB() 
    { 
     // Code. 
    } 
} 

class B : A 
{ 
    sealed override public void methodB() 
    { 
     // Code. 
    } 
} 

Così, nell'esempio di cui sopra mi può impedire il methodB() venga sacrificata per tutte le classi che derivano dalla classe B, ma come faccio a prevenire classe B di ignorare il methodB() in primo luogo?

Aggiornamento: ho perso la parola chiave virtual nella dichiarazione methodB() sulla classe A quando ho postato questa domanda. Corretto

+0

È una nuova funzionalità in C# 4 per sigillare un metodo? –

+0

Se non si sta già eseguendo l'override del metodo, allora non decorarlo con 'virtual', quindi qualsiasi altra cosa non verrà considerata per il binding del metodo sul proprio tipo. –

+0

Credo che i tuoi metodi in classe A dovrebbero essere "virtuali" se stai pianificando di sovrascriverli. – CAbbott

risposta

21

Non è necessario fare nulla. Il modificatore virtual specifica che un metodo può essere sovrascritto. Ometterlo significa che il metodo è 'finale'.

In particolare, un metodo deve essere virtual, abstract o override per essere sovrascritto.

Utilizzando la parola new permetterà al metodo della classe base da nascondere, ma sarà ancora non ignorare che vale a dire quando si chiama A.methodB() si otterrà la versione della classe base, ma se si chiama B.methodB() si otterrà la nuova versione.

+0

È frustrante in un linguaggio che consente di scrivere così tante cose esplicitamente, non c'è una parola chiave per dire esplicitamente "questo non significa essere mai sopraffatti" ", se solo così non lo rendi per errore virtuale più avanti senza considerare il motivo per cui non era in primo piano. –

11

Come lei ha ricordato, è possibile impedire un'ulteriore primario di MethodB in classe B utilizzando sealedconoverride

class B : A 
{ 
    public sealed override void methodB() 
    { 
     Console.WriteLine("Class C cannot override this method now"); 
    } 
} 

uso del sealed modificatore di insiemeoverride impedisce una classe derivata da sovrascrivendo ulteriormente la metodo.

Se non si desidera che methodB in classe A venga sovrascritto da qualsiasi classe secondaria, non contrassegnare tale metodo virtual. Basta rimuoverlo. parola chiave virtual abilitare il metodo a essere sovrascritto in classi figlie

public void methodA() 
{  
} 

Usa sealed parole chiave sulle tue classi per prevenire un ulteriore prioritario della classe

+3

L'uso del modificatore sigillato impedisce a una classe di derivare dalla 'classe A'. Questo non è quello che è stato chiesto. –

+0

@KendallFrey: il titolo della domanda mi ha fatto pensare che si tratta di prevenire ulteriori sovrascritture. Grazie – Shyju

+7

@KendallFrey 'sealed' può essere applicato ai metodi, a condizione che siano sovrascritti. Impedisce * ulteriore * di ignorare le classi derivate (come sottolinea Shyju). – dlev

1

In una classe base, la parola chiave sealed viene utilizzata solo per impedire che una classe venga derivata, ma in classi ereditate può essere utilizzata per impedire a un'altra classe ereditata di eseguire l'override del metodo.

Per impedire che un metodo di classe base venga sottoposto a override, non specificarlo come virtuale. Nell'esempio che hai fornito, la classe B non può ignorare lo methodB perché methodB non è stato contrassegnato come virtuale nella classe originale.

questo compilerà:

class A 
{ 
    public virtual void methodA() 
    { 
     //code 
    } 
    public virtual void methodB() 
    { 
     //code 
    } 
} 
class B:A 
{ 
    public override void methodB() 
    { 
     //code 
    } 
} 

questo non:

class A 
{ 
    public void methodA() 
    { 
     //code 
    } 
    public void methodB() 
    { 
     //code 
    } 
} 
class B:A 
{ 
    public override void methodB() 
    { 
     //code 
    } 
} 

Editted: chiariti e corretti mia dichiarazione originale sulla sigillato parola chiave

+2

'sealed' può essere effettivamente utilizzato su singoli metodi, è solo che' sealed' non può essere utilizzato all'implementazione di livello più alto del metodo; deve essere utilizzato su un metodo che è un override di un'implementazione di base, in pratica annullando la parola chiave "virtuale" da livelli di ereditarietà più elevati quando ne deriva ulteriormente. Quindi, ti sbagli che non può essere usato ma non risolve il suo problema comunque – KeithS

+0

@KeithS grazie per quello. Non ho mai visto prima usarlo per sigillare e sovrascrivere il metodo, ma grazie per avermi insegnato qualcosa di nuovo. Ho modificato la mia risposta in modo appropriato – psubsee2003

5

In C#, una funzione non contrassegnata virtual (che include anche l'override delle funzioni virtuali) è effettivamente sigillato e non può essere sovrascritto. Pertanto, il codice di esempio in realtà non verrà compilato perché la parola chiave override non è valida a meno che non vi sia un metodo contrassegnato virtuale con la stessa firma in una classe base.

Se A.methodB() sono stati segnati virtuale, allora si potrebbe eseguire l'override del metodo da A, ma evitare che venga ulteriormente ignorata nelle classi derivante più indirettamente, utilizzando la parola chiave sealed esattamente come avete dimostrato.

Una cosa da tenere a mente è che, mentre il metodo primario può essere evitata, il metodo nascondere non può. Data la tua attuale definizione di classe A, la seguente definizione di classe B è legale e non c'è niente che si può fare a questo proposito:

class B:A 
{ 
     public new void methodB() 
      { 
        //code 
      } 
    } 

Il new parola chiave fondamentalmente "rompe" l'eredità/sovrascrivendo gerarchia per quello che attiene a questo metodo; qualsiasi riferimento a una classe B, trattato come una classe B (o qualsiasi altro tipo derivato), utilizzerà l'implementazione dalla classe B e ignorerà quella della classe A, a meno che l'implementazione di B non specificatamente la richiamerà. Tuttavia, se dovessi trattare un'istanza di classe B come una classe A (lanciandola o passandola come parametro), la "nuova" implementazione viene ignorata.

Questo differisce dall'override, in cui una classe B che viene trattata come una classe A e sostituisce effettivamente un metodo virtualeB utilizzerà comunque l'override del metodo di classe B. Comprendi anche che il metodo nascosto è dedotto (anche se riceverai un avvertimento sul compilatore); se dichiari un metodo con la stessa firma in una classe derivata e non si specifica né nuovo né sovrascritto, il metodo della classe base verrà nascosto.

+0

Ottime informazioni sul modificatore 'new'. Non lo sapevo nemmeno. – CAbbott