Wann und warum würden Sie eine Klasse besiegeln?


86

In C # und C ++ / CLI wird das Schlüsselwort sealed(oder NotInheritablein VB) verwendet, um eine Klasse vor Vererbungschancen zu schützen (die Klasse ist nicht vererbbar). Ich weiß, dass ein Merkmal der objektorientierten Programmierung die Vererbung ist, und ich bin der Meinung, dass die Verwendung von sealedgegen dieses Merkmal verstößt und die Vererbung stoppt. Gibt es ein Beispiel, das den Nutzen zeigt sealedund wann es wichtig ist, es zu verwenden?

Antworten:


96
  1. In einer Klasse, die Sicherheitsfunktionen implementiert, sodass das ursprüngliche Objekt nicht "verkörpert" werden kann.

  2. Im Allgemeinen habe ich mich kürzlich mit einer Person bei Microsoft ausgetauscht, die mir sagte, sie habe versucht, die Vererbung auf die Stellen zu beschränken, an denen dies wirklich Sinn macht, da sie in Bezug auf die Leistung teuer wird, wenn sie nicht behandelt wird.
    Das versiegelte Schlüsselwort teilt der CLR mit, dass es keine Klasse weiter unten gibt, um nach Methoden zu suchen, und dies beschleunigt die Arbeit.

In den meisten leistungssteigernden Tools auf dem heutigen Markt finden Sie ein Kontrollkästchen, das alle nicht vererbten Klassen versiegelt.
Seien Sie jedoch vorsichtig, denn wenn Sie Plugins oder Assembly Discovery über MEF zulassen möchten, treten Probleme auf.


3
Ich wollte vorsichtig sein, wenn Klassen in wiederverwendeten Bibliotheken versiegelt werden, insbesondere wenn sie von Dritten wiederverwendet und dann (über MEF) wieder in die Codebasis integriert werden. Ihre Codebasis erbt möglicherweise keine bestimmte Klasse, Dritte jedoch.
Louis Kottmann

9
Der Grund Nr. 1 klingt vage, aber wenn wir die meiste Zeit keine "Sicherheitsmerkmale" schreiben, bedeutet das, dass Grund Nr. 1 kaum zutrifft? Grund Nr. 2 ist die Leistungsoptimierung. Über wie viel Leistungsunterschied sprechen wir? Sind sie signifikant genug, um eine Änderung der Definition einer Nicht-Sicherheitsklasse zu rechtfertigen? Selbst wenn die Antwort "Ja" wäre, wäre dies idealerweise eine Compileroption, dh "optimierten Code für alle nicht versiegelten Klassen generieren", anstatt uns Entwickler die Codebasis ändern zu lassen.
RayLuo

1
Wenn es unbehandelt bleibt, wird es in Bezug auf die Leistung teuer. Ist dies sogar mit weniger als einer wahnsinnigen Anzahl verrückter Tests messbar?
t3chb0t

4
Versiegelung saugt. Das macht das Testen schwieriger - ich würde gerne ein paar ASP.NET-Klassen mit FakeItEasy verspotten, aber ich kann nicht, weil sie versiegelt sind.
Warlike Schimpanse

1
Kann nicht mehr mit @RayLuo übereinstimmen. Ich habe es mehrmals getroffen, dass Leute ihre Klassen versiegelt haben, in denen Sicherheit und Leistung kein wirkliches Problem sind. Ihre "Versiegelung" verhinderte einfach mein vernünftiges Bedürfnis, die Klassen zu überschreiben, und machte die Dinge viel schwieriger. Wie Warlike Chimpanzee sagte, ist das Verspotten einer Klasse beim Testen so üblich.
ZZY

15

Ein Nachtrag zu Baboons hervorragender Antwort :

  1. Wenn eine Klasse nicht ist konzipiert für die Vererbung, Unterklassen könnten brechen Klasseninvarianten . Dies gilt natürlich nur, wenn Sie eine öffentliche API erstellen, aber als Faustregel versiegele ich jede Klasse, die nicht explizit für die Unterklasse ausgelegt ist.

In einem verwandten Hinweis, der nur für nicht versiegelte Klassen gilt: Jede erstellte Methode virtualist ein Erweiterungspunkt oder sieht zumindest so aus, als ob sie ein Erweiterungspunkt sein sollte. Das Deklarieren von Methoden virtualsollte ebenfalls eine bewusste Entscheidung sein. (In C # ist dies eine bewusste Entscheidung, in Java nicht.)


EDIT : Einige relevante Links:

Beachten Sie auch, dass Kotlin standardmäßig Klassen versiegelt. Das openSchlüsselwort ist das Gegenteil von Java finaloder sealedC # . (Natürlich gibt es keine allgemeine Übereinstimmung darüber, dass dies eine gute Sache ist .)


23
Das Versiegeln von Klassen verursacht mehr Kopfschmerzen als Nutzen. Ich habe immer wieder Situationen gefunden, in denen Entwickler Klassen versiegelt haben, was mir stundenlange Schwierigkeiten bereitet, was einfach sein sollte. Hör auf, Klassen zu versiegeln, du bist nicht so witzig, wie du denkst. Versiegeln Sie Klassen nur, wenn Sie es überdenken MÜSSEN, und selbst dann. Nur meine Meinung, als der Typ, der sich mit den versiegelten Klassen anderer Leute auseinandersetzen muss, die ich nicht bearbeiten / entsiegeln kann.
Gant Laborde

8
Der Kommentar von @GantMan sollte eigentlich als eine der Antworten auf die Frage des OP angesehen werden, da er im Wesentlichen die Antwort "Wann? Kaum. Warum. Dies? Dies ist der Grund, warum Sie das NICHT tun." Gibt. Gewähren Sie, dass Sie Ihren Kommentar als separate Antwort erneut veröffentlichen und dann Stimmen dafür sammeln sollten. :-)
RayLuo

1
Bezog sich dies auf diese Antwort: stackoverflow.com/a/7777674/3195477 ? Es ist besser, darauf zu verlinken, als die Person (nur) zu benennen
UuDdLrLrSs

2

Das Markieren einer Klasse als Sealedverhindert das Manipulieren wichtiger Klassen, die die Sicherheit gefährden oder die Leistung beeinträchtigen können.

Oft ist das Versiegeln einer Klasse auch dann sinnvoll, wenn eine Utility-Klasse mit festem Verhalten entworfen wird, das wir nicht ändern möchten.

Zum Beispiel bietet der SystemNamespace in C#viele Klassen, die versiegelt sind, wie z String. Wenn es nicht versiegelt ist, könnte es seine Funktionalität erweitern, was unerwünscht sein könnte, da es sich um einen grundlegenden Typ mit gegebener Funktionalität handelt.

Ebenso sind structuresin C#immer implizit versiegelt. Daher kann man eine Struktur / Klasse nicht von einer anderen Struktur ableiten. Der Grund dafür ist, dass structuresnur eigenständige, atomare, benutzerdefinierte Datentypen modelliert werden, die wir nicht ändern möchten.

Wenn Sie Klassenhierarchien erstellen, möchten Sie manchmal einen bestimmten Zweig in der Vererbungskette basierend auf Ihrem Domänenmodell oder Ihren Geschäftsregeln abschließen.

Zum Beispiel sind a Managerund PartTimeEmployeebeide Employees, aber Sie haben nach Teilzeitbeschäftigten in Ihrer Organisation keine Rolle mehr. In diesem Fall möchten Sie möglicherweise versiegeln PartTimeEmployee, um eine weitere Verzweigung zu verhindern. Wenn Sie jedoch stündliche oder wöchentliche Teilzeitbeschäftigte haben, kann es sinnvoll sein, diese zu erben PartTimeEmployee.


Wie wäre eine Erweiterung der String-Klasse unerwünscht? String würde immer noch genau so funktionieren, wie es derzeit funktioniert, und Sie könnten eine abgeleitete Klasse mit zusätzlichen Funktionen haben, wenn dies gewünscht wird. Also, über welches Problem sprechen Sie?
Kevin Wells

Was wäre auch der Sinn, Ihre Vererbungshierarchie zu "begrenzen"? Es würde bedeuten, dass Sie, wenn Sie diese Hierarchie jemals erweitern müssten, zuerst die Elternklasse entsiegeln müssten, was nur ineffizient ist
Kevin Wells

Schauen Sie sich diesen ausgezeichneten Beitrag von Eric Lippert und diese SO-Frage an .
Akshay Khot

Selbst diese Antwort läuft im Grunde auf "Warum sollten Sie einen String ableiten?" Hinaus, führt dann Gründe an, warum Sie einen String ableiten möchten (z. B. nullterminierte Strings) und sagt, Sie sollten ihn einfach ohne Vererbung umgehen. Warum also komplizierter machen und später daran arbeiten müssen, wenn Sie es einfach zuerst entsiegelt lassen und Ihre Optionen offen lassen können
Kevin Wells

Bei der zweiten Frage wäre das Ziel, unerwünschtes Verhalten (abhängig von der Geschäftslogik) zu verhindern. unsealBei Bedarf ist es für die Klasse später einfacher , als sie zu versiegeln und alle davon abhängigen Klassen zu brechen.
Akshay Khot

0

Ich denke, dieser Beitrag hat einen guten Punkt. Der spezielle Fall war, als versucht wurde, eine nicht versiegelte Klasse in eine zufällige Schnittstelle umzuwandeln. Der Compiler gibt keinen Fehler aus. Wenn jedoch versiegelt verwendet wird, gibt der Compiler einen Fehler aus, den er nicht konvertieren kann. Die versiegelte Klasse bietet zusätzliche Sicherheit für den Codezugriff.
https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla


1
Ein Link zu einer Lösung ist willkommen, aber stellen Sie sicher, dass Ihre Antwort ohne sie nützlich ist: Fügen Sie dem Link einen Kontext hinzu, damit Ihre Mitbenutzer eine Vorstellung davon haben, was es ist und warum es dort ist, und zitieren Sie dann den relevantesten Teil der Seite, die Sie verwenden. erneutes Verknüpfen mit, falls die Zielseite nicht verfügbar ist. Antworten, die kaum mehr als ein Link sind, können gelöscht werden.
Baum mit Augen

Es tut mir leid, dass ich nicht vorhatte, es als Antwort zu veröffentlichen, aber es scheint nicht mit anderen Antworten zu tun zu haben, und ich weiß nicht, wo ich es
ablegen soll

1
Ich habe den Beitrag gemäß dem Vorschlag bearbeitet. Ursprünglich möchte ich (vielleicht) nur einen anderen Blickwinkel einbringen, aber ich habe nur eine Abwertung erhalten und wir haben noch nicht über den Inhalt gesprochen. Könnte der -1 bitte den Grund mitteilen?
Strisunshine
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.