2013-08-07 25 views
8

Ecco la mia situazione. In Java posso marcare un metodo come finale nella classe base/super e non c'è modo in cui una classe derivata possa mascherare un metodo della stessa firma. In C#, tuttavia, la nuova parola chiave consente a qualcuno che eredita la mia classe di creare un metodo con la stessa firma.C# impedisce che il metodo della classe base venga nascosto dal nuovo modificatore nella classe derivata

Vedere il mio esempio qui sotto. Devo mantenere pubblico orignal.MyClass per favore non suggerirlo come risposta. Questa sembra essere una funzionalità persa passando da Java a C#

public class orignal.MyClass{ 
    public void MyMethod() 
    { 
    // Do something 
    } 
} 

class fake.MyClass: orignal.MyClass { 
    // How to prevent the following 
    public new void MyMethod() 
    { 
    // Do something different 
    } 
} 

MODIFICA: non è un duplicato.

Tutte le risposte sembrano suggerire, non è possibile impedire che un metodo venga nascosto/ombreggiato in una classe derivata. Ciò è diventato evidente durante la migrazione di un vecchio codice Java in C#. Un metodo finale in Java non consente a nessuno di utilizzare la stessa firma del metodo in qualsiasi classe derivata. Mentre è bello nella maggior parte degli scenari che C# consente un metodo della stessa firma nella classe derivata, sarebbe stato grandioso prevenire un tale comportamento se giustificato.

+0

possibile duplicato di [Qual è l'equivalente di Java finale in C#?] (Http://stackoverflow.com/questions/1327544/what-is-the-equivalent-of-javas-final-in-c). .. –

+2

Come accennato da @Reed, 'raramente ha importanza'. Il tuo codice continuerà a chiamare il metodo originale. –

+1

Non un duplicato. Non sto chiedendo un equivalente. Sto suggerendo che non esiste per questo caso d'uso. – JAson

risposta

9

// Come prevenire le seguenti

Non c'è modo per evitare questo. È permesso dalla lingua.

Si noti che, in pratica, raramente ciò è importante. Se si prevede di utilizzare la classe base come classe, il metodo verrà comunque chiamato. L'utilizzo di new nasconde il metodo solo quando si utilizza DerivedClass da una variabile dichiarata come DerivedClass.

Ciò significa che l'API, se costruita intorno a MyClass, chiamerà sempre MyMethod quando le istanze vengono passate nei tuoi metodi.


Modifica in risposta alle osservazioni:

Se siete preoccupati per le persone sottoclassi la classe in generale, l'unica vera opzione si ha è quello di sigillare il vostro classe:

public sealed class MyClass 
{ 

Ciò impedirà alle persone di creare una sottoclasse interamente. Se vuoi consentire alle persone di derivare dalla tua classe, tuttavia, non c'è modo di impedire che nascondano il tuo metodo nella loro classe.

+0

Ho fatto una modifica. È molto facile per qualcuno che usa la mia API (ad esempio Alice) creare un wrapper che abbia una classe con lo stesso nome e quindi se questo wrapper dovesse essere usato da un'altra persona, consentirà ad Alice di ridefinire il comportamento di MyMethod () e probabilmente ingannare uno sviluppatore finale ignaro – JAson

+1

@JAson Non proprio: lo sviluppatore dovrebbe includere lo spazio dei nomi dell'altro utente invece del tuo o qualificare completamente il tipo. In ogni caso, dovrebbero sapere cosa stanno facendo. –

+0

@JAson che è _overriding_, non _hiding_. Nascondere un metodo non ha alcun impatto sulla classe base. –

3

Non è possibile impedire la mascheratura di un metodo o una proprietà pubblica, ma perché? Ci vuole un'azione deliberata da parte di chiunque estenda la classe base per fare ciò (cioè devono digitare new), quindi hanno deciso di farlo, perché provare a fermarli?

Forse hai bisogno di cambiare un po 'il tuo schema? Se l'extender deve usare il tuo metodo di base, allora puoi mettere qualcosa di critico in esso, costringendoli quindi a chiamarlo. Naturalmente questo è maleodorante se non eseguito correttamente, quindi se si utilizza questo approccio, contrassegnare il metodo come virtual, quindi nella documentazione (o nei commenti dell'intestazione del metodo) si indica che il metodo di base deve essere chiamato. In questo modo eviti che l'extender debba nascondere/mascherare il tuo metodo (anche se potrebbe ancora), ma possono ancora estenderlo se lo desiderano.

0

Sto assumendo davvero si vuole evitare che qualcuno sovrascrivendo il metodo - che nasconde un metodo con new non può essere evitato, ma non pone alcun rischio per la classe di base, in modo che non dovrebbe essere un problema.

In C# i metodi non sono sovrascrivibili per impostazione predefinita. In questo modo puoi semplicemente impedire a qualcuno di sovrascrivere un metodo di base non contrassegnandolo come virtual o abstract. In Java i metodi sono virtuali per impostazione predefinita, quindi sigillare un metodo utilizzando final è necessario per impedire l'override.

+0

La domanda sembra abbastanza chiara che riguarda la nuova parola chiave e non impedisce la sovrascrittura ... – Chris

+0

Nota che in C# puoi anche marcare un metodo come 'sealed' che funziona praticamente identicamente a' final' in java. In realtà puoi sigillare un metodo virtuale. Cioè avere un metodo virtuale sovrascritto da una classe derivata, ma averlo sigillato per impedire ulteriori ri-definizioni. – Servy

+1

@JAson È certamente * possibile * sigillare un metodo in una classe base. Puoi assolutamente evitare che venga sovrascritto, ma non puoi mai impedire che venga oscurato usando * nuovo *, come tutti gli altri ti hanno detto. Questo è solo un dato di fatto. – Servy

0

penso che l'unico modo è quello di creare l'interfaccia mettere la tua definizione di un metodo all'interno di esso, poi lasciare la classe originale per implementare l'interfaccia e implementare il metodo in modo esplicito:

interface IAnimal 
    { 
     string diary(string notes, int sleephours); 
    } 

    class Dogs:IAnimal 
    {   

virtual public string voice() 
     { 
      string v = "Hao Hao"; return v; 
     } 
     string IAnimal.diary(string notes,int sleephours) 
     { 
      return notes + sleep.ToString() + " hours"; 
     } 

    } 

    class Cats:Dogs 
    { 
     public override string voice() 
     { 
      string v = "Miao Miao"; return v; 
     } 
    } 

Non utilizzerà il diario() metodo tramite istanza Cats.

Problemi correlati