2009-02-16 4 views
12

Un gran numero di classi del framework .Net sono contrassegnati come 'sigillati', che impedisce di ereditare queste classi con il vostro. Sicuramente questo va contro la natura dell'orientamento agli oggetti, in cui è possibile estendere e ridefinire il comportamento degli oggetti esistenti.Perché la parola chiave 'sealed' esiste in .Net?

Esiste una buona ragione per l'esistenza della parola chiave "sealed"?

Come esempio, NotifyCollectionChangedEventArgs in Silverlight è sigillata. Volevo creare la mia versione di ObservableCollection che ha sostenuto AddRange e removeRange, ma la versione di Silverlight di NCCEA non lo fa forniscono un costruttore che supporta più elementi per le NewItems e OldItems proprietà, che sono già definiti come ILists. Solitamente, mi piacerebbe solo estendere la classe con la mia variante che ha annullato le proprietà NewItems e , ma in questo caso non è possibile e non vedo perché debba essere il caso.

+5

Si potrebbe voler leggere il post sul blog di Eric Lippert sul perché la maggior parte delle cose nel framework .NET sono sigillate: http://blogs.msdn.com/ericlippert/archive/2004/01/22/61803.aspx – gix

+0

perché java ha il modificatore di classe 'final'/s –

risposta

21

Progettare classi (o framework) per essere estensibili non è banale, e mettere semplicemente l'ereditarietà non è l'unico principio della programmazione orientata agli oggetti.

Quindi sealed esiste per consentire allo sviluppatore/designer di esprimere e conservare tali intenzioni. Sigillare una classe può anche semplificarsi la vita riducendo il carico di manutenzione. Consente allo sviluppatore originale di controllare il modo in cui la classe (o framework) è estesa, in modo che possano apportare modifiche interne senza doversi preoccupare di rompere le modifiche ad altri codici.

Un principio è che gli sviluppatori devono sigillare qualsiasi classe foglia per impostazione predefinita. Quindi, quando lo sviluppatore crea intenzionalmente una classe non sigillata, li costringe a pensare all'estendibilità.


Rif: Eric Lippert - Why Are So Many Of The Framework Classes Sealed?

+0

Penso di leggere qualcosa di sbagliato qui. Leggo che afferma che è stato fatto per preservare le intenzioni degli sviluppatori sui framework ** e ** dovremmo sigillare qualsiasi classe per impostazione predefinita per facilitare lo sviluppo locale. Ciò sembra contraddire la prima idea, perché se sigilli tutte le classi farai molti problemi a chiunque utilizzi il tuo framework. Oppure, cosa dovremmo fare se pensiamo di dover estendere una classe sigillata? Quindi, forse aiuta se puoi dare un buon esempio pratico su come e quando dovrebbe essere usato e perché è bene che esista. Potresti per favore? :-) – cregox

+0

@Cawas In realtà sto solo sostenendo di fornire solo il punto di estensione dell'ereditarietà quando è progettato e pensato. Idealmente una base di codice più semplice renderà la vita più facile riducendo i costi di manutenzione a lungo termine. –

+0

Bene, allora stavo cercando di capire, senza alcun background, la stessa identica cosa posta sulla domanda. * Perché 'sealed' esiste anche *. E la tua risposta non l'ha fatto per me. Ora posso vedere da dove vieni. E quello che mi è mancato è tutto nei dettagli ... Permettimi di proporre una modifica. ;-) – cregox

2

La risposta breve è, perché Microsoft ha detto così. La risposta più lunga è che Microsoft ha fornito un meccanismo per estendere le classi sigillate, chiamate metodi di estensione.

In generale, è una cattiva idea estendere le classi a cui non si ha il codice sorgente. Ad esempio, non si conosce il metodo di base chiamante per i dati interni dell'oggetto. Sì, puoi usare reflector o qualsiasi altra cosa per capirlo, ma in generale è molto meglio usare i metodi di composizione o di estensione.

Devi anche considerare che cos'è l'ereditarietà. Non è solo un modo per modificare la classe, ma fornisce anche il polimorfismo. Cosa succede se si cambia la semantica di, ad esempio, la classe stringa, quindi si passa la nuova classe di stringa a un oggetto che si aspetta che una stringa agisca in un modo specifico? sigillato impone essenzialmente il contratto che questo oggetto funzionerà sempre nel modo in cui te lo aspetti.

+0

Ma se ho una nuova classe SuperString che estende la stringa, e non si comporta come le altre classi si aspettano, allora sicuramente questo è il mio problema come implementatore della classe SuperString. Sembra sciocco sigillare una classe solo perché un altro sviluppatore * potrebbe * romperlo. –

+0

Questo andrebbe bene se si stesse usando una stringa solo nel proprio codice. Ma classi come String sono usate in tutto il framework. Microsoft vuole assicurarsi che non cambino per il proprio utilizzo. –

1

Mentre sono d'accordo sul fatto che .NET probabilmente sigilli troppo, è generalmente per proteggere l'integrità di un ecosistema. Quando una delle tue priorità è mantenere stabile il tuo framework/API/runtime generale e ci sono delle interdipendenze piuttosto fragili tra le classi, potrebbe essere più sicuro impedire alle persone di scavalcare quel comportamento e inavvertitamente destabilizzare le funzionalità di base.

Anche se, di nuovo, tendo a pensare che il team di .NET sigilli troppe classi. La chiusura a volte può essere una semplice pigrizia da parte dello sviluppatore perché un design di classe adeguato sarebbe troppo lavoro.

6

Questa risposta da una domanda in qualche modo correlato ho chiesto oggi potrebbe contribuire a chiarire ai fini della tenuta di una classe:

mi sono trovato a chiedere la stessa domanda fino a quando ho iniziato a lavorare su librerie riutilizzabili della mia. Molte volte si finisce con determinate classi che non possono essere estese senza richiedendo sequenze oscure o arcane di chiamate dall'implementatore.

Quando permettendo che la vostra classe da esteso, si deve chiedere: se uno sviluppatore estende la mia classe, e passa questa nuova classe alla mia biblioteca, posso trasparente lavorare con questo nuovo classe? Posso lavorare correttamente con questa nuova classe ? Questa nuova classe sarà veramente andando a comportarsi allo stesso modo?

ho trovato che la maggior parte del tempo i classi sigillate in .NET Framework hanno determinati requisiti previsti il cofano che non siete a conoscenza, e che, data l'attuale realizzazione non può essere sicuro esposto a sottoclassi.

Liskov Substition and Composition

Ora seguire quel link e upvote il vero autore.

2

Senza scavare troppo a fondo, è chiaro che Microsoft preferisce sigillare una classe quando ci sono potenziali problemi di sicurezza, manutenzione o retrocompatibilità che dovrà affrontare a valle. Ad esempio, System.String è sigillato per motivi di sicurezza e prestazioni.

In questo caso particolare, è necessario chiedere a uno sviluppatore Microsoft perché scelga di sigillare quella classe. Tuttavia, la letteratura di orientamento architetturale che ho letto ultimamente tende a favorire un approccio di "sigillo a meno che tu non conosca lo ". Questa letteratura tende a sposarsi usando i metodi di estensione laddove possibile. (Non sto dicendo che sono d'accordo con questo, sto solo dicendo che è quello che ho letto ultimamente.)

Anche se la classe non fosse sigillata, le proprietà in questione potrebbero essere state lasciate non virtuali, che ti lascerebbe ancora il torrente qui.

Nel tuo scenario specifico, sceglierei i metodi di estensione con i tuoi nomi univoci. È tutto ciò che puoi fare.

0

Dipende, ci sono classi che sono destinati ad essere solo un'istanza (eredità, se esiste, viene utilizzato solo per semplificare l'implementazione), altre classi hanno lo scopo di essere ereditato per fornire un'implementazione spesifica.

classi sigillate avere alcuni vantaggi:

  • non hanno alcun metodo virtuale, in modo da non devono preoccuparsi di metodi non "sicuri" eccezione- attuate imperativi.
  • Se una classe è immutabile può preservare e garantire l'immutabilità.

In caso contrario, se si desidera decorare una classe sigillata con i metodi "comfort", utilizzare i metodi di estensione (C# 3.0).

0

Solo perché qualcosa è un oggetto, non significa che dovrebbe essere sempre aperto a tutti per estendere o ridefinire il suo comportamento.

Una buona analogia sarebbe una porta e una serratura. La natura di una porta è quella di permettere alle persone di attraversarlo, questo è ciò per cui è stato costruito. Tuttavia, molte porte sono progettate con serrature che possono limitare la capacità delle persone di attraversarle. La decisione se una porta ha una serratura e se quella serratura è bloccata di default è lasciata all'architetto della stanza, in base a cosa c'è nella stanza e chi dovrebbe avere accesso ad essa, non sul fatto che si tratta di una porta.

Naturalmente, può essere frustrante se la maggior parte delle porte di un determinato edificio sono bloccate di default, specialmente se ce n'è una che si vuole veramente passare. :-) Sono stato lì da solo e ho fatto la stessa domanda. La risposta breve è che a volte quando si progetta un framework complesso, le persone tendono ad errare un po 'sul lato più cauto e hanno classi sigillate di default, a meno che non ci sia uno scenario esplicito che ne richieda l'estensione.

1

Suggerirei che non vi è alcuna buona ragione per sigillare classi diverse da quella di proteggere l'ignorante, ma intendo innocente. Conoscete il vecchio detto "date loro abbastanza corda e si impiccheranno". Lasciali oscillare dico io. Forse questo è il mio background in C++, ma sono abbastanza tranquillo sapendo che ho il potere di riempire completamente le cose se non sono diligente.

Tendo a programmare dall'interfaccia. Le interfacce sono ovviamente pubbliche e chiunque è libero di fornire la propria implementazione che aderisce al contratto espresso dall'interfaccia. Le mie lezioni concrete che implementano queste interfacce tendono ad essere una preoccupazione privata e sono contrassegnate come interne e/o private. Non sento di aver bisogno di sigillare queste lezioni.

Laddove il riutilizzo del codice è desiderabile, evito il riutilizzo attraverso l'ereditarietà, favorendo la composizione e altre tecniche.

La sigillatura può anche essere valida per tipi considerati normali tipi di dati precedenti, ma non sono convinto del tutto.

0

Uno degli usi pratici in cui ho trovato utile la parola chiave sealed è evitare "Problemi di classe Fragile". Ecco un video che mostra uno dei delicati problemi di classe di base http://www.youtube.com/watch?v=xnA3RUJcyY4

Lasciatemi spiegare un po 'in dettaglio.

Considerare lo scenario seguente in cui è presente una classe padre denominata "DbParent" con un metodo virtuale "Inserisci".

class DbParent {

public virtual void Insert() 
    { 
     Console.WriteLine("Parent insert"); 
    } 

}

Qui di seguito è una semplice classe figlia con la sua implementazione “Inserisci” che viene installato in vari luoghi.

class DbChildClass : DbParent 
    { 
    public void Insert() 
    { 
     Console.WriteLine("Child inserts"); 
    } 

}

Ora diciamo che dopo alcuni mesi di sviluppatori classe genitrice di implementazione senza capire l'impatto sulle classi figlie andare e aggiungere un nuovo metodo “Add”. Questo metodo "Aggiungi" chiama internamente il metodo "Inserisci" (di seguito è riportato lo snippet di codice per lo stesso).

class DbParent 
    { 
    public void Add() // Adds method with out consulting 
    { 
    this.Insert(); 
    } 

    public virtual void Insert() 
    { 
     Console.WriteLine("Parent insert"); 
    } 
    } 

ora i programmi client che invocano il metodo “Add” con la creazione di oggetti di classe bambino si aspettano che il “bambino” di classe “Inserisci” l'attuazione dovrebbe essere chiamato.

DbChildClass o = new DbChildClass(); 
    o.Add(); 
    Console.Read(); 

Ma Whoaaaa, se si esegue il codice qui sotto vedrete la classe padre “Inserisci” si chiama, che non è previsto.

Quindi vorrei andare a contrassegnare la classe come "sigillata" per evitare tali problemi.