Quando e perché sigilleresti una lezione?


89

In C # e C ++ / CLI la parola chiave sealed(o NotInheritablein VB) viene utilizzata per proteggere una classe da qualsiasi possibilità di ereditarietà (la classe non sarà ereditabile). So che una caratteristica della programmazione orientata agli oggetti è l'ereditarietà e sento che l'uso di sealedva contro questa caratteristica, ferma l'ereditarietà. C'è un esempio che mostra i vantaggi sealede quando è importante utilizzarlo?

Risposte:


100
  1. Su una classe che implementa funzionalità di sicurezza, in modo che l'oggetto originale non possa essere "impersonato".

  2. Più in generale, ho recentemente scambiato con una persona in Microsoft, che mi ha detto di aver cercato di limitare l'eredità ai luoghi in cui aveva davvero senso, perché diventa costoso dal punto di vista delle prestazioni se non trattata.
    La parola chiave sealed dice al CLR che non esiste una classe più in basso per cercare metodi e ciò accelera le cose.

Nella maggior parte degli strumenti per il miglioramento delle prestazioni oggi sul mercato, troverai una casella di controllo che sigillerà tutte le tue classi che non sono ereditate.
Fai attenzione però, perché se vuoi consentire la scoperta di plugin o assembly tramite MEF, incorrerai in problemi.


3
Intendevo fare attenzione a sigillare le classi nelle librerie riutilizzate, specialmente se vengono riutilizzate da terze parti e quindi reintegrate (tramite MEF) nella base di codice. La tua base di codice potrebbe non ereditare una determinata classe, ma terze parti lo faranno.
Louis Kottmann

10
Il motivo # 1 suona vago ma, supponendo che non scriviamo "caratteristiche di sicurezza" il più delle volte, significa che il motivo # 1 difficilmente si applica? Il motivo n. 2 è per l'ottimizzazione delle prestazioni. Di quale differenza di prestazioni stiamo parlando? Sono abbastanza significativi da giustificare la modifica della definizione di una classe non di sicurezza? Anche se la risposta fosse "sì", questa sarebbe idealmente un'opzione del compilatore, cioè "genera codice ottimizzato per tutte le classi non sigillate", piuttosto che costringere noi sviluppatori a modificare la base del codice.
RayLuo

1
diventa costoso dal punto di vista delle prestazioni se non trattato è anche misurabile con meno di un numero folle di test pazzi?
t3chb0t

4
La sigillatura fa schifo. Rende i test più difficili: vorrei deridere un paio di classi ASP.NET con FakeItEasy, ma non posso perché sono sigillate.
Warlike Chimpanzee

2
Non posso essere più d'accordo con @RayLuo. Ho riscontrato più volte che le persone hanno sigillato le loro classi in cui la sicurezza e le prestazioni non sono davvero un problema. Il loro "sigillato" ha semplicemente impedito il mio ragionevole bisogno di ignorare le lezioni, reso le cose molto più difficili. Come ha detto Warlike Chimpanzee, prendere in giro una classe è così comune nei test.
ZZY

15

Un'aggiunta all'eccellente risposta di Baboon :

  1. Se una classe non è progettata per l'ereditarietà, le sottoclassi potrebbero rompere le invarianti di classe . Questo si applica davvero solo se stai creando un'API pubblica, ovviamente, ma come regola generale, sigillo qualsiasi classe non progettata esplicitamente per essere sottoclasse.

In una nota correlata, applicabile solo alle classi non sigillate: qualsiasi metodo creato virtualè un punto di estensione, o almeno sembra che dovrebbe essere un punto di estensione. Anche la dichiarazione dei metodi virtualdovrebbe essere una decisione consapevole. (In C # questa è una decisione consapevole; in Java non lo è.)


EDIT : alcuni link rilevanti:

Si noti inoltre che Kotlin sigilla le classi per impostazione predefinita; la sua openparola chiave è l'opposto di Java finalo sealeddi C # . (A dire il vero, non esiste un accordo universale che questa sia una buona cosa .)


26
Le lezioni di sigillamento causano più mal di testa che benefici. Ho trovato continuamente situazioni in cui gli sviluppatori hanno classi sigillate, causandomi ore di difficoltà in ciò che dovrebbe essere semplice. Smettila di suggellare le lezioni, non sei arguto come pensi di essere. Sigilla le classi solo se DEVI, e anche allora, riconsiderare. Solo la mia opinione, come il ragazzo che ha a che fare con le classi sigillate di altre persone che non posso modificare / rimuovere.
Gant Laborde

9
Il commento di @GantMan dovrebbe effettivamente essere considerato come una delle risposte alla domanda dell'OP, perché essenzialmente dà una risposta come "Quando? Difficilmente. Perché? Questo è il motivo per cui NON lo fai". Concediti di ripubblicare il tuo commento come risposta separata e quindi raccogliere voti per esso. :-)
RayLuo

1
Questo si riferiva a questa risposta: stackoverflow.com/a/7777674/3195477 ? È meglio collegarsi ad esso piuttosto che nominare (solo) la persona
UuDdLrLrSs

2

Contrassegnare una classe come Sealedimpedisce la manomissione di classi importanti che possono compromettere la sicurezza o influire sulle prestazioni.

Molte volte, sigillare una classe ha senso anche quando si progetta una classe di utilità con un comportamento fisso, che non vogliamo cambiare.

Ad esempio, lo Systemspazio dei nomi in C#fornisce molte classi che sono sigillate, come String. Se non sigillato, sarebbe possibile estenderne le funzionalità, il che potrebbe essere indesiderabile, in quanto è un tipo fondamentale con una determinata funzionalità.

Allo stesso modo, structuresin C#sono sempre implicitamente sigillati. Quindi non si può derivare una struttura / classe da un'altra struttura. Il motivo è che structuresvengono utilizzati per modellare solo tipi di dati autonomi, atomici e definiti dall'utente , che non si desidera modificare.

A volte, quando crei gerarchie di classi, potresti voler limitare un determinato ramo nella catena di ereditarietà, in base al tuo modello di dominio o alle regole aziendali.

Ad esempio, un Managere PartTimeEmployeesono entrambi Employee, ma non hai alcun ruolo dopo i dipendenti part-time nella tua organizzazione. In questo caso, potresti voler sigillare PartTimeEmployeeper evitare ulteriori ramificazioni. D'altra parte, se hai dipendenti part-time orari o settimanali, potrebbe avere senso ereditarli da PartTimeEmployee.


In che modo l'estensione della classe String sarebbe indesiderabile? String funzionerebbe ancora esattamente come funziona attualmente e potresti avere una classe derivata con funzionalità aggiuntive quando lo desideri, quindi di quale problema stai parlando?
Kevin Wells

Inoltre quale sarebbe il punto di "limitare" la tua gerarchia ereditaria? Significherebbe che se mai avessi bisogno di estendere quella gerarchia dovresti prima togliere il sigillo alla classe genitore, il che è semplicemente inefficiente
Kevin Wells

Dai un'occhiata a questo eccellente post di Eric Lippert e a questa domanda SO .
Akshay Khot

1
Anche quella risposta fondamentalmente si riduce a "Perché dovresti voler derivare String?", Quindi prosegue menzionando i motivi per cui potresti voler derivare String (stringhe con terminazione null per esempio) e dice che dovresti semplicemente aggirarlo senza ereditarietà. Allora perché renderlo più complicato e risolverlo in un secondo momento quando puoi semplicemente lasciarlo aperto e lasciare aperte le tue opzioni
Kevin Wells

Per la seconda domanda, l'obiettivo sarebbe prevenire comportamenti indesiderati (a seconda della logica aziendale). È più facile andare in unsealclasse più tardi, se necessario, piuttosto che sigillarlo e rompere tutte le classi che dipendono da esso.
Akshay Khot

0

Penso che questo post abbia qualche buon punto, il caso specifico era quando si tentava di eseguire il cast di una classe non sigillata su qualsiasi interfaccia casuale, il compilatore non genera errori; ma quando viene utilizzato sealed, il compilatore genera un errore che non può convertire. La classe Sealed offre una protezione aggiuntiva dall'accesso al codice.
https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla


1
Un collegamento a una soluzione è il benvenuto, ma assicurati che la tua risposta sia utile senza di essa: aggiungi un contesto attorno al collegamento in modo che i tuoi colleghi utenti abbiano un'idea di cosa sia e perché sia ​​lì, quindi cita la parte più pertinente della pagina che tu " re collegamento a nel caso in cui la pagina di destinazione non è disponibile. Le risposte che sono poco più di un collegamento possono essere eliminate.
Baum mit Augen

Scusa non avevo intenzione di postarlo come risposta, ma sembra non correlato ad altre risposte e non so dove metterlo
strisunshine

1
Ho modificato il post secondo il suggerimento. Inizialmente vorrei solo contribuire con un'angolazione diversa (forse), ma ho ricevuto solo un voto negativo e non abbiamo ancora parlato del contenuto, il -1 potrebbe gentilmente far sapere il motivo?
strisunshine
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.