Dans le billet de blog 2008 de Kathleen Dollard , elle présente une raison intéressante d'utiliser des classes imbriquées dans .net. Cependant, elle mentionne également que FxCop n'aime pas les classes imbriquées. Je suppose que les gens qui écrivent des règles FxCop ne sont pas stupides, donc il doit y avoir un raisonnement derrière cette position, mais je n'ai pas été en mesure de le trouver.
93
Réponses:
Utilisez une classe imbriquée lorsque la classe que vous imbriquez n'est utile que pour la classe englobante. Par exemple, les classes imbriquées vous permettent d'écrire quelque chose comme (simplifié):
Vous pouvez créer une définition complète de votre classe en un seul endroit, vous n'avez pas besoin de parcourir les cerceaux PIMPL pour définir le fonctionnement de votre classe, et le monde extérieur n'a pas besoin de voir quoi que ce soit de votre implémentation.
Si la classe TreeNode était externe, vous devrez soit créer tous les champs,
public
soit créer un tas deget/set
méthodes pour l'utiliser. Le monde extérieur aurait une autre classe polluant leur intelligence.la source
À partir du didacticiel Java de Sun:
Pourquoi utiliser des classes imbriquées? Il existe plusieurs raisons impérieuses d'utiliser des classes imbriquées, parmi lesquelles:
Regroupement logique des classes: si une classe n'est utile qu'à une seule autre classe, il est logique de l'intégrer dans cette classe et de garder les deux ensemble. L'imbrication de ces "classes d'assistance" rend leur package plus simple.
Encapsulation accrue: considérez deux classes de niveau supérieur, A et B, où B a besoin d'accéder aux membres de A qui seraient autrement déclarés privés. En masquant la classe B dans la classe A, les membres de A peuvent être déclarés privés et B peut y accéder. De plus, B lui-même peut être caché du monde extérieur.<- Cela ne s'applique pas à l'implémentation en C # des classes imbriquées, cela ne s'applique qu'à Java.Code plus lisible et maintenable: l'imbrication de petites classes dans des classes de niveau supérieur rapproche le code de l'endroit où il est utilisé.
la source
Motif singleton entièrement paresseux et thread-safe
source: http://www.yoda.arachsys.com/csharp/singleton.html
la source
Cela dépend de l'utilisation. J'utiliserais rarement une classe imbriquée publique, mais j'utiliserais tout le temps des classes imbriquées privées. Une classe imbriquée privée peut être utilisée pour un sous-objet destiné à être utilisé uniquement à l'intérieur du parent. Un exemple de cela serait si une classe HashTable contient un objet Entry privé pour stocker des données en interne uniquement.
Si la classe est destinée à être utilisée par l'appelant (en externe), j'aime généralement en faire une classe autonome distincte.
la source
En plus des autres raisons énumérées ci-dessus, il y a une autre raison à laquelle je peux penser non seulement pour utiliser des classes imbriquées, mais en fait des classes imbriquées publiques. Pour ceux qui travaillent avec plusieurs classes génériques partageant les mêmes paramètres de type générique, la possibilité de déclarer un espace de noms générique serait extrêmement utile. Malheureusement, .Net (ou du moins C #) ne prend pas en charge l'idée d'espaces de noms génériques. Ainsi, pour atteindre le même objectif, nous pouvons utiliser des classes génériques pour atteindre le même objectif. Prenons l'exemple de classes suivantes liées à une entité logique:
Nous pouvons simplifier les signatures de ces classes en utilisant un espace de noms générique (implémenté via des classes imbriquées):
Ensuite, grâce à l'utilisation de classes partielles comme suggéré par Erik van Brakel dans un commentaire précédent, vous pouvez séparer les classes en fichiers imbriqués séparés. Je recommande d'utiliser une extension Visual Studio comme NestIn pour prendre en charge l'imbrication des fichiers de classe partiels. Cela permet aux fichiers de classe "namespace" d'être également utilisés pour organiser les fichiers de classe imbriqués dans un dossier de la même manière.
Par exemple:
Entity.cs
Entity.BaseDataObject.cs
Entity.BaseDataObjectList.cs
Entity.IBaseBusiness.cs
Entity.IBaseDataAccess.cs
Les fichiers de l'explorateur de solutions Visual Studio seraient alors organisés comme tels:
Et vous implémenteriez l'espace de noms générique comme suit:
User.cs
User.DataObject.cs
User.DataObjectList.cs
User.IBusiness.cs
User.IDataAccess.cs
Et les fichiers seraient organisés dans l'explorateur de solutions comme suit:
Ce qui précède est un exemple simple d'utilisation d'une classe externe comme espace de noms générique. J'ai construit des "espaces de noms génériques" contenant 9 paramètres de type ou plus dans le passé. Il était fastidieux de devoir garder ces paramètres de type synchronisés sur les neuf types dont tous avaient besoin pour connaître les paramètres de type, en particulier lors de l'ajout d'un nouveau paramètre. L'utilisation d'espaces de noms génériques rend ce code beaucoup plus gérable et lisible.
la source
Si je comprends bien l'article de Katheleen, elle propose d'utiliser une classe imbriquée pour pouvoir écrire SomeEntity.Collection au lieu d'EntityCollection <SomeEntity>. À mon avis, c'est une façon controversée de vous éviter de taper. Je suis presque sûr que dans le monde réel, les collections d'applications auront une certaine différence dans les implémentations, vous devrez donc créer une classe séparée de toute façon. Je pense que l'utilisation du nom de classe pour limiter la portée d'une autre classe n'est pas une bonne idée. Il pollue l'intellisense et renforce les dépendances entre les classes. L'utilisation d'espaces de noms est un moyen standard de contrôler la portée des classes. Cependant, je trouve que l'utilisation de classes imbriquées comme dans @hazzen comment est acceptable à moins que vous n'ayez des tonnes de classes imbriquées, ce qui est un signe de mauvaise conception.
la source
J'utilise souvent des classes imbriquées pour masquer les détails de l'implémentation. Un exemple de la réponse d'Eric Lippert ici:
Ce modèle devient encore meilleur avec l'utilisation de génériques. Voir cette question pour deux exemples sympas. Alors je finis par écrire
au lieu de
Je peux aussi avoir une liste générique de
Equality<Person>
mais pasEqualityComparer<Person, int>
tandis que
n'est pas possible. C'est l'avantage de la classe imbriquée héritant de la classe parent.
Un autre cas (de même nature - masquer l'implémentation) est celui où vous souhaitez rendre les membres d'une classe (champs, propriétés, etc.) accessibles uniquement pour une seule classe:
la source
Une autre utilisation non encore mentionnée pour les classes imbriquées est la ségrégation des types génériques. Par exemple, supposons que l'on veuille avoir des familles génériques de classes statiques qui peuvent prendre des méthodes avec différents nombres de paramètres, avec des valeurs pour certains de ces paramètres, et générer des délégués avec moins de paramètres. Par exemple, on souhaite avoir une méthode statique qui peut prendre un
Action<string, int, double>
et donner unString<string, int>
qui appellera l'action fournie en passant 3.5 comme ledouble
; on peut aussi souhaiter avoir une méthode statique qui peut prendre un anAction<string, int, double>
et donner un anAction<string>
, en passant7
comme leint
et5.3
comme ledouble
. En utilisant des classes imbriquées génériques, on peut faire en sorte que les invocations de méthode soient quelque chose comme:ou, parce que les derniers types dans chaque expression peuvent être déduits même si les premiers ne le peuvent pas:
L'utilisation des types génériques imbriqués permet de dire quels délégués sont applicables à quelles parties de la description de type globale.
la source
Les classes imbriquées peuvent être utilisées pour les besoins suivants:
la source
Comme nawfal a mentionné l'implémentation du modèle Abstract Factory, ce code peut être étendu pour obtenir un modèle de clusters de classes qui est basé sur le modèle Abstract Factory.
la source
J'aime imbriquer des exceptions qui sont uniques à une seule classe, c'est-à-dire. ceux qui ne sont jamais jetés d'un autre endroit.
Par exemple:
Cela permet de garder vos fichiers de projet bien rangés et non pleins d'une centaine de petites classes d'exception tronquées.
la source
Gardez à l'esprit que vous devrez tester la classe imbriquée. S'il est privé, vous ne pourrez pas le tester de manière isolée.
Vous pouvez cependant le rendre interne en conjonction avec l'
InternalsVisibleTo
attribut . Cependant, ce serait la même chose que de rendre un champ privé interne uniquement à des fins de test, ce que je considère comme une mauvaise auto-documentation.Ainsi, vous souhaiterez peut-être implémenter uniquement des classes imbriquées privées impliquant une faible complexité.
la source
oui pour ce cas:
la source
Sur la base de ma compréhension de ce concept, nous pourrions utiliser cette fonctionnalité lorsque les classes sont liées les unes aux autres sur le plan conceptuel. Je veux dire que certains d'entre eux sont un élément complet dans notre entreprise, comme des entités qui existent dans le monde DDD qui aident un objet racine agrégé à compléter sa logique métier.
Afin de clarifier, je vais montrer cela via un exemple:
Imaginez que nous ayons deux classes comme Order et OrderItem. Dans la classe de commande, nous allons gérer tous les orderItems et dans OrderItem, nous conservons des données sur une seule commande pour clarification, vous pouvez voir les classes ci-dessous:
la source