Classe déclarée à l’intérieur d’une autre classe en C #

Je travaille sur un code hérité et j’ai rencontré quelque chose dont je ne suis pas sûr. Nous avons une class y qui est déclarée à l’intérieur d’une autre class x . Class y n’est utilisée que dans class x mais ma question est de savoir pourquoi ne pas créer un fichier de classe séparé et y mettre la class y au lieu de la déclarer dans la class x ? N’est-ce pas une violation de la POO ou est-ce juste une question de style, car elle n’est utilisée que dans cette classe. Je suis en train de remanier une partie de ce code et ma première réaction serait de séparer class y out dans son propre fichier.

 namespace Library { public class x { // methods, properties, local members of class x class y { // methods, properties, local members of class y } } } 

Vous créez une classe interne car elle n’est utilisée que dans le cadre de la classe x et elle s’inscrit logiquement dans la factorisation / architecture de la classe x.

La classe y pourrait également être au courant des détails d’implémentation de la classe x qui ne sont pas destinés à être connus du public.

Cela a des implications sur les permissions. Une “classe y” de niveau supérieur serait “interne” – cependant, ici “y” est privé à “x”. Cette approche est utile pour les détails d’implémentation (par exemple, les lignes de cache, etc.). De même, y a access à tous les états privés de x .

Il y a aussi des implications avec les génériques; x.y est générique “de T”, hérité de la classe externe. Vous pouvez voir ceci ici, où Bar a la pleine utilisation de T – et notez que tous les champs statiques de Bar ont une scope maximale.

 class Foo { void Test(T value) { Bar bar = new Bar(); bar.Value = value; } class Bar { public T Value { get; set; } } } 

Souvent, les gens pensent à tort qu’ils doivent définir Bar comme Bar – ceci est (à présent) doublement générique – c’est-à-dire Foo – où TOld est le T (maintenant indisponible) de Foo . Alors ne fais pas ça! Ou si vous voulez qu’il soit doublement générique, choisissez des noms différents. Heureusement, le compilateur vous en avertit …

Ce code convient à la raison exacte pour laquelle vous avez donné – “la classe y n’est utilisée que dans la classe x”. Ce sont des types nesteds et l’une des directives pour les utiliser est que les types nesteds doivent être étroitement liés à leur type de déclaration et ne doivent pas être utiles en tant que type d’usage général. De cette façon, la classe nestede est inaccessible aux autres classes, mais vous permet néanmoins de suivre les principes orientés object.

Je viens de passer en revue le code que je mets à jour (et j’ai écrit à l’origine) et j’ai supprimé toutes les classes nestedes. Malheureusement, j’ai initialement utilisé la classe nestede en dehors de la classe dans laquelle elle avait été définie. Le fait de déplacer des classes nestedes a fait une énorme différence pour moi car j’avais à l’origine une mauvaise conception.

Si Y est seulement utilisé dans X et ne sera jamais utilisé en dehors de X, je dirais de le garder là

Je pense que ça va, tant que la classe contenue n’est utilisée que comme utilitaire. J’utilise ce type de construction par exemple pour définir des types de retour complexes pour les méthodes privées.

Laissez-moi vous donner un exemple de l’utilisation de classes nestedes qui pourraient clarifier le moment où ce type d’architecture est approprié. J’ai récemment eu besoin de générer un tableau HTML en tirant les colonnes sélectionnées d’un tableau de données et en les “faisant pivoter” pour que les lignes deviennent des colonnes et vice versa. Dans mon cas, il y avait deux opérations essentielles: pivoter les données et générer des sorties assez complexes (je ne faisais pas que montrer les données: chaque colonne de données / ligne de tableau était sujette à des opérations d’extraction de titre, de génération de tags d’image, etc. utilisant ainsi un SQL Pivot n’était pas vraiment correct non plus).

Après une première tentative de création d’une classe pour faire tout le travail, j’ai reconnu qu’une grande partie des données / méthodes se divisaient en trois partitions distinctes: le traitement des en-têtes, le traitement des lignes et le pivotement. Ainsi, j’ai décidé qu’une meilleure approche serait d’encapsuler la logique pour “en-tête” et “ligne” dans des classes séparées et nestedes. Cela m’a permis de séparer les données de chaque ligne et de programmer les opérations de pivot très proprement (en appelant un object ligne distinct pour chaque colonne de votre tableau de données). À la fin des opérations de pivot, j’ai généré une sortie en appelant l’object d’en-tête, puis chaque object de ligne génère à son tour sa sortie dans la classe principale.

Les classes séparées n’étaient pas appropriées car A) les classes nestedes avaient besoin de données de la classe principale et B) le traitement était très spécifique et pas utile ailleurs. Simplement programmer une grande classe était simplement plus compliqué en raison de la confusion entourant des termes tels que “colonne” et “ligne” qui différaient selon que vous parliez de données ou de la sortie HTML. En outre, c’était un travail inhabituel dans la mesure où je produisais du code HTML dans ma classe professionnelle. Je voulais donc séparer la logique métier pure de la génération de l’interface utilisateur. Au final, les classes nestedes fournissaient l’équilibre parfait entre encapsulation et partage de données.

Vous pouvez toujours réorganiser votre classe y dans un autre fichier, mais utilisez une classe parallèle. L’avantage de ceci est que vous avez toujours une classe par fichier et que vous n’avez pas à vous soucier du déplacement de la déclaration en dehors de la classe x.

Par exemple, vous pourriez avoir un fichier de code: xycs qui ressemblerait à quelque chose

 partial class X { class Y { //implementation goes here } }