In Kathleen Dollards Blogbeitrag von 2008 stellt sie einen interessanten Grund vor, verschachtelte Klassen in .net zu verwenden. Sie erwähnt jedoch auch, dass FxCop keine verschachtelten Klassen mag. Ich gehe davon aus, dass die Leute, die FxCop-Regeln schreiben, nicht dumm sind, also muss es Gründe für diese Position geben, aber ich konnte sie nicht finden.
93
Antworten:
Verwenden Sie eine verschachtelte Klasse, wenn die Klasse, die Sie verschachteln, nur für die einschließende Klasse nützlich ist. Mit verschachtelten Klassen können Sie beispielsweise Folgendes schreiben: (vereinfacht):
Sie können Ihre Klasse an einem Ort vollständig definieren. Sie müssen nicht durch PIMPL-Rahmen springen, um zu definieren, wie Ihre Klasse funktioniert, und die Außenwelt muss nichts von Ihrer Implementierung sehen.
Wenn die TreeNode-Klasse extern wäre, müssten Sie entweder alle Felder erstellen
public
oder eine Reihe vonget/set
Methoden erstellen , um sie zu verwenden. Die Außenwelt würde eine andere Klasse haben, die ihre Intelligenz verschmutzt.quelle
Aus dem Java-Tutorial von Sun:
Warum verschachtelte Klassen verwenden? Es gibt mehrere zwingende Gründe für die Verwendung verschachtelter Klassen, darunter:
Logische Gruppierung von Klassen - Wenn eine Klasse nur für eine andere Klasse nützlich ist, ist es logisch, sie in diese Klasse einzubetten und die beiden zusammenzuhalten. Durch das Verschachteln solcher "Hilfsklassen" wird das Paket rationalisiert.
Erhöhte Kapselung - Betrachten Sie zwei Klassen der obersten Ebene, A und B, bei denen B Zugriff auf Mitglieder von A benötigt, die andernfalls als privat deklariert würden. Durch das Ausblenden von Klasse B in Klasse A können die Mitglieder von A als privat deklariert werden und B kann auf sie zugreifen. Außerdem kann B selbst vor der Außenwelt verborgen sein.<- Dies gilt nicht für die Implementierung verschachtelter Klassen durch C #, sondern nur für Java.Besser lesbarer, wartbarer Code - Durch das Verschachteln kleiner Klassen in Klassen der obersten Ebene wird der Code näher an dem Ort platziert, an dem er verwendet wird.
quelle
Völlig faul und threadsicheres Singleton-Muster
Quelle: http://www.yoda.arachsys.com/csharp/singleton.html
quelle
Das hängt von der Nutzung ab. Ich würde selten eine öffentlich verschachtelte Klasse verwenden, aber die ganze Zeit private verschachtelte Klassen. Eine private verschachtelte Klasse kann für ein Unterobjekt verwendet werden, das nur innerhalb des übergeordneten Objekts verwendet werden soll. Ein Beispiel hierfür wäre, wenn eine HashTable-Klasse ein privates Eintragsobjekt enthält, um Daten nur intern zu speichern.
Wenn die Klasse vom Aufrufer (extern) verwendet werden soll, mache ich sie im Allgemeinen gerne zu einer separaten eigenständigen Klasse.
quelle
Zusätzlich zu den anderen oben aufgeführten Gründen gibt es einen weiteren Grund, den ich mir vorstellen kann, nicht nur verschachtelte Klassen zu verwenden, sondern tatsächlich öffentlich verschachtelte Klassen. Für diejenigen, die mit mehreren generischen Klassen arbeiten, die dieselben generischen Typparameter verwenden, wäre die Möglichkeit, einen generischen Namespace zu deklarieren, äußerst nützlich. Leider unterstützt .Net (oder zumindest C #) die Idee generischer Namespaces nicht. Um dasselbe Ziel zu erreichen, können wir generische Klassen verwenden, um dasselbe Ziel zu erreichen. Nehmen Sie die folgenden Beispielklassen für eine logische Entität:
Wir können die Signaturen dieser Klassen vereinfachen, indem wir einen generischen Namespace verwenden (implementiert über verschachtelte Klassen):
Durch die Verwendung von Teilklassen, wie von Erik van Brakel in einem früheren Kommentar vorgeschlagen, können Sie die Klassen in separate verschachtelte Dateien aufteilen. Ich empfehle die Verwendung einer Visual Studio-Erweiterung wie NestIn, um das Verschachteln der Teilklassendateien zu unterstützen. Auf diese Weise können die Klassendateien "Namespace" auch verwendet werden, um die verschachtelten Klassendateien in einem Ordner zu organisieren.
Beispielsweise:
Entity.cs
Entity.BaseDataObject.cs
Entity.BaseDataObjectList.cs
Entity.IBaseBusiness.cs
Entity.IBaseDataAccess.cs
Die Dateien im Visual Studio Solution Explorer würden dann wie folgt organisiert:
Und Sie würden den generischen Namespace wie folgt implementieren:
User.cs
User.DataObject.cs
User.DataObjectList.cs
User.IBusiness.cs
User.IDataAccess.cs
Und die Dateien würden im Lösungs-Explorer wie folgt organisiert:
Das Obige ist ein einfaches Beispiel für die Verwendung einer äußeren Klasse als generischen Namespace. Ich habe in der Vergangenheit "generische Namespaces" mit 9 oder mehr Typparametern erstellt. Es war mühsam, diese Typparameter über die neun Typen hinweg synchron zu halten, die alle zur Kenntnis der Typparameter erforderlich waren, insbesondere beim Hinzufügen eines neuen Parameters. Die Verwendung generischer Namespaces macht diesen Code weitaus übersichtlicher und lesbarer.
quelle
Wenn ich Katheleens Artikel richtig verstehe, schlägt sie vor, eine verschachtelte Klasse zu verwenden, um SomeEntity.Collection anstelle von EntityCollection <SomeEntity> schreiben zu können. Meiner Meinung nach ist es eine kontroverse Möglichkeit, Ihnen das Tippen zu ersparen. Ich bin mir ziemlich sicher, dass Anwendungssammlungen in der Praxis einige Unterschiede bei den Implementierungen aufweisen. Daher müssen Sie ohnehin eine separate Klasse erstellen. Ich denke, dass es keine gute Idee ist, den Klassennamen zu verwenden, um den Umfang anderer Klassen einzuschränken. Es verschmutzt die Intelligenz und stärkt die Abhängigkeiten zwischen Klassen. Die Verwendung von Namespaces ist eine Standardmethode zur Steuerung des Klassenbereichs. Ich finde jedoch, dass die Verwendung verschachtelter Klassen wie im @ hazzen-Kommentar akzeptabel ist, es sei denn, Sie haben Tonnen verschachtelter Klassen, was ein Zeichen für schlechtes Design ist.
quelle
Ich verwende oft verschachtelte Klassen, um Implementierungsdetails auszublenden. Ein Beispiel aus Eric Lipperts Antwort hier:
Dieses Muster wird mit der Verwendung von Generika noch besser. In dieser Frage finden Sie zwei coole Beispiele. Also schreibe ich am Ende
anstatt
Auch kann ich eine generische Liste haben,
Equality<Person>
aber nichtEqualityComparer<Person, int>
wohingegen
Ist nicht möglich. Dies ist der Vorteil einer verschachtelten Klasse, die von einer übergeordneten Klasse erbt.
Ein anderer Fall (der gleichen Art - Implementierung ausblenden) besteht darin, dass Sie die Mitglieder einer Klasse (Felder, Eigenschaften usw.) nur für eine einzelne Klasse zugänglich machen möchten:
quelle
Eine andere Verwendung, die für verschachtelte Klassen noch nicht erwähnt wurde, ist die Trennung von generischen Typen. Angenommen, man möchte einige generische Familien statischer Klassen haben, die Methoden mit einer unterschiedlichen Anzahl von Parametern sowie Werte für einige dieser Parameter verwenden und Delegaten mit weniger Parametern generieren können. Zum Beispiel wünscht man sich eine statische Methode, die ein nehmen
Action<string, int, double>
und ein ergeben kann,String<string, int>
das die bereitgestellte Aktion, die 3.5 übergibt, als das aufruftdouble
; Man kann sich auch eine statische Methode wünschen, die ein an nehmenAction<string, int, double>
und ein ergebenAction<string>
kann und7
als dasint
und5.3
als das übergehtdouble
. Mit generischen verschachtelten Klassen kann man festlegen, dass die Methodenaufrufe wie folgt aussehen:oder weil die letzteren Typen in jedem Ausdruck abgeleitet werden können, obwohl die ersteren nicht:
Durch die Verwendung der verschachtelten generischen Typen kann festgestellt werden, welche Delegaten auf welche Teile der Gesamttypbeschreibung anwendbar sind.
quelle
Die verschachtelten Klassen können für folgende Anforderungen verwendet werden:
quelle
Wie nawfal die Implementierung des Abstract Factory-Musters erwähnte, kann dieser Code erweitert werden, um ein Klassencluster- Muster zu erzielen , das auf dem Abstract Factory-Muster basiert.
quelle
Ich mag es, Ausnahmen zu verschachteln, die nur für eine einzelne Klasse gelten, d. H. diejenigen, die niemals von einem anderen Ort geworfen werden.
Beispielsweise:
Auf diese Weise bleiben Ihre Projektdateien aufgeräumt und nicht voll mit hundert kleinen Ausnahmeklassen.
quelle
Denken Sie daran, dass Sie die verschachtelte Klasse testen müssen. Wenn es privat ist, können Sie es nicht isoliert testen.
Sie können es jedoch in Verbindung mit dem
InternalsVisibleTo
Attribut intern machen . Dies wäre jedoch dasselbe, als würde ein privates Feld nur zu Testzwecken intern gemacht, was ich als schlechte Selbstdokumentation betrachte.Daher möchten Sie möglicherweise nur private verschachtelte Klassen mit geringer Komplexität implementieren.
quelle
ja für diesen Fall:
quelle
Basierend auf meinem Verständnis dieses Konzepts könnten wir diese Funktion verwenden, wenn Klassen konzeptionell miteinander in Beziehung stehen. Ich meine, einige von ihnen sind ein Element in unserem Geschäft, wie Entitäten, die in der DDD-Welt existieren und die einem aggregierten Stammobjekt helfen, seine Geschäftslogik zu vervollständigen.
Zur Verdeutlichung werde ich dies anhand eines Beispiels zeigen:
Stellen Sie sich vor, wir haben zwei Klassen wie Order und OrderItem. In der Auftragsklasse werden wir alle orderItems verwalten und in OrderItem speichern wir Daten zu einer einzelnen Bestellung zur Verdeutlichung. Sie können die folgenden Klassen sehen:
quelle