Also wollte ich von a sealed class
in csharp erben und wurde verbrannt. Es gibt nur eine Möglichkeit, die Versiegelung aufzuheben, wenn Sie Zugriff auf die Quelle haben.
Dann dachte ich: "Warum sealed
gibt es überhaupt?" vor 4 Monaten. Ich konnte es nicht herausfinden, obwohl ich viele Dinge darüber gelesen habe, wie zum Beispiel:
- Jon Skeets Wünsche " Klassen wurden standardmäßig in .NET versiegelt. "
- Bevorzugen Sie die Komposition gegenüber der Vererbung?
- "Sie sollten nicht alle Klassen versiegeln (...)"
- Wie macht man sich über eine Sealed-Klasse lustig?
Ich habe seitdem versucht, das alles zu verdauen, aber es ist einfach zu viel für mich. Irgendwann gestern habe ich es nochmal versucht. Ich habe sie alle noch einmal gescannt und noch ein paar mehr:
- Warum sollte eine Klasse nicht "abstrakt" oder "endgültig / versiegelt" sein?
- In über 15 Jahren Programmierung habe ich zum ersten Mal von SOLID gehört, als Antwort auf eine Frage, die bereits verlinkt ist, und ich habe es offensichtlich nicht alle vor 4 Monaten gelesen
Schließlich habe ich mich nach langem Nachdenken entschlossen , die ursprüngliche Frage auf der Grundlage des neuen Titels stark zu bearbeiten.
Die alte Frage war zu weit gefasst und subjektiv. Grundsätzlich wurde gefragt:
- Im alten Titel: Ein guter Grund, versiegelt zu verwenden
- Im Körper: Wie kann man eine versiegelte Klasse richtig modifizieren? Erbschaft vergessen? Komposition verwenden?
Aber jetzt, zu verstehen (was ich nicht gestern) , dass alles sealed
tut , ist Vererbung zu verhindern , und wir können und in der Tat verwenden sollten Komposition der Vererbung , wurde mir klar , was ich brauchte , war praktische Beispiele.
Ich denke, meine Frage hier ist genau das, was Mr.Mindor mir in einem Chat vorgeschlagen hat (und das war es auch schon immer) : Wie kann das Entwerfen für die Vererbung zusätzliche Kosten verursachen?
quelle
Antworten:
Das ist nicht so schwer zu verstehen.
sealed
wurde SPEZIELL für Microsoft entwickelt, um ihr Leben zu erleichtern, viel Geld zu sparen und ihren Ruf zu verbessern. Da es sich um ein Sprachfeature handelt, kann es auch jeder andere verwenden, aber DU wirst es wahrscheinlich nie brauchen, Sealed zu verwenden.Die meisten Leute beschweren sich darüber, dass sie eine Klasse nicht erweitern können, und wenn sie dies tun, sagen sie, dass jeder weiß, dass die Entwickler dafür verantwortlich sind, dass sie richtig funktionieren. Das ist richtig, mit AUSNAHME, dass dieselben Leute keine Ahnung von der Geschichte von Windows haben und eines der Probleme
sealed
zu lösen versucht.Nehmen wir an, ein Entwickler hat eine .Net-Core-Klasse erweitert (weil sie nicht vorhanden war) und dafür gesorgt, dass sie perfekt funktioniert. Ja, für den Entwickler. Der Entwickler liefert das Produkt an den Kunden. Die Entwickler-App funktioniert hervorragend. Der Kunde ist glücklich. Das leben ist gut.
Jetzt veröffentlicht Microsoft ein neues Betriebssystem, das das Beheben von Fehlern in dieser speziellen .NET-Core-Klasse umfasst. Der Kunde möchte mit der Zeit gehen und wählt die Installation des neuen Betriebssystems. Plötzlich funktioniert die Anwendung, die dem Kunden so gut gefällt, nicht mehr, da die in der .Net-Core-Klasse behobenen Fehler nicht berücksichtigt wurden.
Wer wird dafür verantwortlich gemacht?
Diejenigen, die mit der Geschichte von Microsoft vertraut sind, wissen, dass das neue Betriebssystem von Microsoft die Schuld trägt und nicht die Anwendungssoftware, die Windows-Bibliotheken missbraucht hat. Dann muss Microsoft das Problem beheben und nicht das Anwendungsunternehmen, das das Problem erstellt hat. Dies ist einer der Gründe, warum Windows-Code aufgebläht wurde. Nach dem, was ich gelesen habe, ist der Windows-Betriebssystemcode mit einem bestimmten Wenn-Dann-Code übersät, der prüft, ob eine bestimmte Anwendung und Version ausgeführt wird. Wenn ja, führen Sie eine spezielle Verarbeitung durch, damit das Programm funktioniert. Das ist eine Menge Geld, das von Microsoft ausgegeben wird, um die Inkompetenz eines anderen Unternehmens zu beheben.
Die Verwendung von
sealed
beseitigt das obige Szenario nicht vollständig, hilft jedoch.quelle
sealed
standardmäßig verwendet werden, es sei denn, sie wurden speziell entsiegelt, nur weil so wenige Klassen tatsächlich für die Vererbung entworfen wurden. Es ist viel wahrscheinlicher, dass Ihre Klasse nicht dafür gebaut wurde, dies zu unterstützen, und Sie sollten sicherstellen, dass Sie diese Entwicklungszeit verbracht haben, wenn Sie sich Mühe geben, sie als nicht versiegelt zu markieren.sealed
. Wenn es tatsächlich die Standardoption wäre, würde dies bedeuten, dass jemand, der von einem Typ erbt, weiß, dass er dafür gebaut ist.String
und diese dann nach der Sicherheitsprüfung, aber vor der E / A-Operation verändert? Ich glaube, diese Art von Szenario ist der Grund, warum JavaString
markiert istfinal
(ähnlich wiesealed
) und ich wette, dass die gleiche Logik einige C # -Entscheidungen untermauert.sealed
wird verwendet, um anzuzeigen, dass der Schreiber der Klasse die Vererbung nicht geplant hat. Nicht weniger, nicht mehr.Das richtige Entwerfen einer Schnittstelle ist für viele Programmierer bereits schwierig genug. Das ordnungsgemäße Entwerfen einer Klasse, die möglicherweise vererbt werden kann, fügt Schwierigkeiten und Codezeilen hinzu. Mehr geschriebene Codezeilen bedeuten mehr zu wartenden Code. Um diese zunehmende Schwierigkeit zu vermeiden,
sealed
können Sie nachweisen, dass die Klasse nie vererbt werden sollte. In diesem Zusammenhang ist das Versiegeln einer Klasse eine einwandfreie Lösung für ein Problem .Stellen Sie sich den Fall vor, von dem die Klasse
CustomBoeing787
abgeleitet istAirliner
. DiesCustomBoeing787
setzt einige geschützte Methoden außer KraftAirliner
, jedoch nicht alle. Wenn der Entwickler genügend Zeit hat und es sich lohnt, kann er die Klasse einzeln testen, um sicherzustellen, dass alles wie erwartet funktioniert, auch in einem Kontext, in dem nicht überschriebene Methoden aufgerufen werden (z. B. geschützte Setter, die den Status des Objekts ändern). Wenn derselbe Entwickler (1) keine Zeit hat, (2) keine zusätzlichen Hunderte oder Tausende von Dollar für seinen Chef / Kunden ausgeben möchte oder (3) keinen zusätzlichen Code schreiben möchte, den er nicht hat brauche jetzt (YAGNI), dann kann er:Geben Sie den Code entweder so frei, wie er ist, da es das Anliegen der Programmierer ist, dieses Projekt später zu warten, um mögliche Fehler zu beheben.
oder markieren Sie die Klasse
sealed
, um den zukünftigen Programmierern explizit anzuzeigen, dass diese Klasse nicht geerbt werden soll und dass das Entsiegeln und Verwenden der Klasse als übergeordnetes Element auf eigenes Risiko erfolgen sollte.Ist es eine gute Idee, so viele Klassen wie möglich oder so wenige wie möglich zu besiegeln? Aus meiner Erfahrung gibt es keine endgültige Antwort. Einige Entwickler neigen dazu,
sealed
zu viel zu verwenden. Anderen ist es egal, wie die Klasse vererbt wird und welches Problem sie verursachen kann. Bei einer solchen Verwendung ähnelt das Problem demjenigen, bei dem bestimmt wird, ob Programmierer zwei oder vier Leerzeichen zum Einrücken verwenden sollen: Es gibt keine richtige Antwort.quelle
tl;dr
. Entweder "Nein, es gibt keinen guten Grund" oder "Ich glaube, es gibt keinen guten Grund, aber ich weiß es auch nicht." . Für mich ist "keine endgültige Antwort" eine davon.sealed
wird verwendet, um anzuzeigen, dass der Schreiber der Klasse die Vererbung nicht geplant hat. Das ist dein einziger guter Grund.String
und diese dann nach der Sicherheitsprüfung, aber vor der E / A-Operation verändert? Ich glaube, diese Art von Szenario ist der Grund, warum JavaString
markiert istfinal
(ähnlich wiesealed
) und ich wette, dass die gleiche Logik einige C # -Entscheidungen untermauert.Wenn eine Klasse versiegelt ist, kann Code, der diesen Typ verwendet, genau wissen, womit sie zu tun haben.
Jetzt in C #
string
istsealed
, können Sie nicht davon erben, aber nehmen wir für eine Sekunde an, dass das nicht der Fall war. Wenn Sie das getan haben, könnte jemand eine Klasse wie diese schreiben:Dies wäre nun eine Zeichenfolgenklasse, die alle Arten von Eigenschaften verletzt, von denen die Designer
string
wussten, dass sie wahr sind. Sie wussten, dass dieEquals
Methode transitiv sein würde, das ist nicht. Heck, diese Gleichheitsmethode ist nicht einmal symmetrisch, da eine Zeichenfolge gleich sein könnte, aber es wäre nicht gleich zu dieser Zeichenfolge. Ich bin sicher, dass es alle Arten von Programmierern gibt, die Code unter der Annahme geschrieben haben, dass dieToString
Methode vonstring
keine Ausnahme für Nicht-Null-Werte auslöst. Sie können jetzt diese Annahme verletzen.Es gibt eine beliebige Anzahl anderer Klassen, für die wir dies tun könnten, und alle möglichen anderen Annahmen, gegen die wir verstoßen könnten. Wenn Sie die Sprachfunktion für entfernen
sealed
dann müssen die Sprachdesigner jetzt damit beginnen, solche Dinge in ihrem gesamten Bibliothekscode zu berücksichtigen. Sie müssen alle Arten von Überprüfungen durchführen, um sicherzustellen, dass erweiterte Typen der Typen, die sie verwenden möchten, "richtig" geschrieben werden, was eine sehr teure Sache sein kann (sowohl in der Entwicklungszeit als auch zur Laufzeit). Indem sie eine Klasse versiegeln können, können sie sicherstellen, dass dies nicht möglich ist und dass Aussagen zu den Implementierungsdetails ihrer eigenen Typen nicht verletzt werden können, mit Ausnahme der Typen, die absichtlich erweitert werden sollen. Für die Typen, die erweitert werden sollen, muss der Sprachcode wesentlich defensiver im Umgang mit ihnen sein.quelle
sealed
Funktionen eingebaut, die für uns nicht zugänglich sind. Es erklärt immer noch nicht, warum es außerhalb eines so engen Rahmens verwendet wird, und da es so eng wie Compiler-Code ist , erklärt es nicht einmal diesealed
Existenz.string
Typ ist kein Compiler-Code. Es ist Teil des Sprachcodes. Ganz anders. Auf jeden Fall habe ich nur ein Beispiel ausgewählt. Sie könnten fast jede versiegelte Klasse in der gesamten BCL aufnehmen und dies als Beispiel verwenden.Enh? Nicht oft. Ich werde nur versiegelt verwendet , wenn ich eine unveränderliche Art haben (oder eine andere Begrenzung) , die wirklich wirklich unveränderlich bleiben muss und kann ich nicht vertrauen Erben diese Anforderung furfill ohne Einführung subtil, catastropic Fehler in das System.
Wir verwenden die Vererbung für diejenigen Dinge, die nicht standardmäßig sind. Selbst wenn die Komposition der Vererbung vorgezogen wird (und dies auch ist), bedeutet dies nicht, dass die Vererbung verworfen werden muss. Dies bedeutet, dass die Vererbung einige intrinsische Probleme hat, die sie in die Design- und Code-Wartbarkeit einführt, und dass die Komposition (im Allgemeinen) mit weniger Problemen dasselbe bewirkt. Und es bedeutet, dass selbst wenn die Komposition bevorzugt wird, die Vererbung für bestimmte Teilmengen von Problemen gut ist.
Ich meine nicht sein zu gemein , aber wenn Sie schon jetzt nur noch fester und Unit - Tests gehören, sollten Sie vielleicht aus underneith Ihrem Rock raus und tatsächlich Code schreiben. Die Dinge sind nicht eindeutig und in den seltensten Fällen ist "immer X tun" oder "niemals Y verwenden" oder "Z ist am besten" der richtige Weg (wie es scheint, dass Sie aufgrund der Ansichten Ihrer Frage dazu tendieren). Während Sie Code schreiben, können Sie Fälle sehen, in denen
sealed
es gut sein könnte, und Fälle, in denen es Sie betrübt - genau wie bei jedem anderen Kompromiss.quelle
sealed
.Lesen Sie zunächst den Beitrag von Eric Lippert, warum Microsoft ihre Klassen besiegelt.
http://blogs.msdn.com/b/ericlippert/archive/2004/01/22/61803.aspx
Zweitens existiert das versiegelte Schlüsselwort, um genau das zu tun, was es tut - die Vererbung zu verhindern. Es gibt viele Situationen, in denen Sie die Vererbung verhindern möchten. Stellen Sie sich eine Klasse vor, für die Sie eine Sammlung haben. Wenn Ihr Code davon abhängt, dass diese Klasse auf bestimmte Weise funktioniert, möchten Sie nicht, dass jemand eine der Methoden oder Eigenschaften in dieser Klasse überschreibt und das Fehlschlagen Ihrer Anwendung verursacht.
Drittens fördert die Verwendung von Sealed die Komposition gegenüber der Vererbung, was eine gute Angewohnheit ist. Die Verwendung von Komposition anstelle von Vererbung bedeutet, dass Sie nicht gegen Liskovs Substitutionsprinzip verstoßen können und dem Open / Closed-Prinzip folgen.
sealed
ist daher ein Schlüsselwort, das Sie dabei unterstützt, zwei der fünf wichtigsten Prinzipien der oo-Programmierung zu befolgen. Ich würde sagen, das macht es zu einem sehr wertvollen Feature.quelle
Ich denke, dass diese Frage keine objektive Antwort hat und dass alles von Ihrer Perspektive abhängt.
Eine Seite, einige Leute wollen, dass alles "offen" ist, und die Verantwortung dafür, dass alles richtig funktioniert, liegt bei der Person, die die Klasse erweitert. Aus diesem Grund können Klassen standardmäßig vererbt werden. Und warum Java-Methoden standardmäßig alle virtuell sind.
Auf der anderen Seite möchten einige, dass standardmäßig alles geschlossen ist und Optionen zum Öffnen bereitgestellt werden. In diesem Fall ist es der Autor der Basisklasse, der sicherstellen muss, dass alles, was er "offen" macht, in jeder erdenklichen Weise sicher zu gebrauchen ist. Aus diesem Grund sind in C # alle Methoden standardmäßig nicht virtuell und müssen zum Überschreiben als virtuell deklariert werden. Es ist auch für diejenigen Menschen, die "offene" Vorgaben umgehen müssen. Als würde man die Klasse versiegelt / final machen, weil sie sehen, dass jemand, der von der Klasse abstammt, ein großes Problem für das Design ihrer eigenen Klasse ist.
quelle
sealed
kippen. Wie können wir von ihnen erben? Ich lese nur, dass wir es nicht können. Je. Ich weiß es nicht. Ich bin jetzt seit 4 Monaten auf und ab gegangen, seit ich zum ersten Mal von Sealed gehört habe. Und ich weiß noch nicht , wie es richtig zu tun , wenn ich brauche etwas auf einer versiegelte Klasse zu ändern. Also sehe ich keine "Option zum Öffnen"!Das Problem mit Sealed in C # ist, dass es ziemlich endgültig ist. In den 7 Jahren der kommerziellen C # -Entwicklung wurde es nur in Microsoft .NET-Klassen verwendet, in denen meines Erachtens ein legitimer Grund dafür bestand, eine Framework-Klasse zu erweitern, um angepasstes Verhalten zu implementieren. Da die Klasse versiegelt war, konnte ich dies nicht .
Es ist unmöglich, eine Klasse zu schreiben, die über jede mögliche Verwendung nachdenkt und entscheidet, dass keine von ihnen legitim ist. Wenn die Framework-Sicherheit davon abhängig ist, dass die Klasse nicht vererbt wird, liegt ebenfalls ein Sicherheitsentwurfsfehler vor.
Zusammenfassend bin ich also der festen Überzeugung, dass versiegelt keinen nützlichen Zweck erfüllt, und nichts, was ich bisher hier gelesen habe, hat diese Ansicht geändert.
Ich kann sehen, dass es bisher drei Argumente gegeben hat, die das bisher Gesiegelte rechtfertigen.
Argument 1 ist, dass es eine Fehlerquelle beseitigt, wenn Leute von Klassen erben und dann besseren Zugriff auf die Interna dieser Klasse haben, ohne die Interna wirklich richtig zu verstehen.
Argument 2 ist, dass, wenn Sie eine Microsoft-Klasse erweitern und dann Microsoft eine Fehlerbehebung in dieser Klasse implementieren, Ihre Erweiterung sich jedoch auf diesen Fehler stützt, Ihr Code jetzt kaputt ist, Microsoft die Schuld erhält und dies verhindert
Argument 3 ist, dass ich als Entwickler der Klasse die Wahl habe, sie im Rahmen meines Entwurfs der Klasse zu erweitern.
Argument 1 scheint ein Argument zu sein, dass Sie als Endprogrammierer nicht wissen, wie man meinen Code verwendet. Das mag der Fall sein, aber wenn Sie mir weiterhin erlauben, auf die Objektschnittstelle zuzugreifen, gilt immer noch, dass ich Ihr Objekt verwende und es aufrufe, ohne zu verstehen, wie es zu verwenden ist, und auf diese Weise genauso viel Schaden anrichten kann . Dies ist eine schwache Rechtfertigung für die Notwendigkeit der Versiegelung.
Ich verstehe, woher die sachliche Grundlage für arg 2 stammt. Insbesondere, wenn Microsoft Win32-API-Aufrufe durch zusätzliche Betriebssystemprüfungen überprüft, um fehlerhafte Aufrufe zu identifizieren, die die allgemeine Stabilität von Windows XP im Vergleich zu Windows NT verbessert haben, aber kurzfristig dazu geführt haben, dass viele Apps bei der Veröffentlichung von Windows XP beschädigt wurden. Microsoft hat dies behoben, indem "Regeln" für diese Überprüfungen eingefügt wurden, um zu sagen, dass es ein bekannter Fehler ist, wenn App X diese Regel verletzt
Argument 2 ist ein schlechtes Argument, da Sealed im besten Fall keinen Unterschied dazu macht, denn wenn es einen Fehler in der .NET-Bibliothek gibt, haben Sie keine andere Wahl, als eine Lösung zu finden, und wenn die Microsoft-Korrektur herauskommt, ist dies sehr wahrscheinlich bedeutet, dass Ihre Arbeit, die vom fehlerhaften Verhalten abhängt, jetzt fehlerhaft ist. Unabhängig davon, ob Sie dies mithilfe der Vererbung oder eines anderen zusätzlichen Wrapper-Codes umgangen haben, wird Ihre Arbeit unterbrochen, wenn der Code behoben ist.
Argument 3 ist das einzige Argument, das irgendeine Substanz hat, um sich selbst zu rechtfertigen. Aber es ist immer noch schwach. Das widerspricht einfach der Wiederverwendung von Code.
quelle
It is impossible to write a class thinking about every possible way it could be used
- Das ist genau der Grund, warum viele Framework-Klassen versiegelt sind ... Es muss nicht mehr überlegt werden, wie jemand die Klasse erweitern könnte.Ich verwende das
sealed
Schlüsselwort nur für Klassen, die nur statische Methoden enthalten.quelle
static
stattdessen?Wie meine Frage zeigt, bin ich hier kein Experte. Aber ich sehe keinen Grund
sealed
, überhaupt zu existieren.Es scheint gemacht zu sein, um Code-Architekten beim Entwerfen einer Schnittstelle zu helfen. Wenn Sie eine Klasse schreiben möchten, die in der Wildnis veröffentlicht wird und von der viele Menschen erben, kann das Ändern von Elementen in dieser Klasse zu einer Unterbrechung für zu viele Menschen führen. So können wir es versiegeln und niemand kann erben. "Problem gelöst".
Sieht so aus, als würde man "eine Stelle abdecken und eine andere aufdecken". Und es löst nicht einmal ein Problem - es beseitigt nur ein Werkzeug : die Vererbung. Wie jedes Tool hat es viele Verwendungen und das Erben von einer instabilen Klasse ist ein Risiko, das Sie eingehen. Wer dieses Risiko eingeht, sollte es besser wissen.
Vielleicht könnte es ein Schlüsselwort geben
stable
, damit die Leute wissen, dass es sicherer ist, davon zu erben.quelle
sealed
kein nützliches Werkzeug für die Framework-Designer ist. Klassen in einem Framework sollten Black Boxes sein. Sie sollten nicht über die Interna einer Klasse Bescheid wissen müssen, um sie richtig verwenden zu können. Doch genau das verlangt die Vererbung.