Quelle est la meilleure façon de structurer et de nommer des fichiers contenant des classes génériques portant le même nom?

14

Dans mon projet actuel, j'ai rencontré la nécessité de créer des classes génériques avec le même nom, mais différents nombres de paramètres génériques. Par exemple:

MyClass<T1>
MyClass<T1, T2>
MyClass<T1, T2, T3>

Étant donné que je veux tous ces éléments dans le même espace de noms, je ne sais pas comment structurer et nommer mes classes et fichiers?

Si nous suivons l'idée que nous devrions avoir des classes limitées à une par fichier et que les fichiers doivent être dans une structure de dossiers qui représente la hiérarchie des espaces de noms et que le nom du fichier doit correspondre au nom de la classe, comment gérer cette situation ?

Ce que je demande vraiment ici, c'est que dois-je nommer le fichier qui contient MyClass<T1>et que dois-je nommer le fichier qui contient MyClass<T1, T2>? Je ne demande pas quels devraient être les noms des paramètres de type.

Stephen
la source
Donnez-nous quelques exemples spécifiques qui décrivent le problème plus en détail. Les exemples que vous avez fournis sont trop ... euh, génériques. Qu'entendez-vous par "comment structurer et nommer mes classes et mes fichiers?"
Robert Harvey
Microsoft le fait lui-même en ajoutant simplement un nombre au paramètre type. Voir la documentation Tuple
Pete
@Pete: Cela ne s'applique vraiment qu'à Tuple. Microsoft utilise également leTKey, TValue convention. Func a un TResultparamètre de type. Bien que je suis d' accord que vous pouvez utiliser T1, T2etc. pour un nombre variable de paramètres d'entrée qui n'ont pas autrement utilisations spécifiques comme TKeyet TValue.
Robert Harvey
@RobertHarvey Eh bien, oui, mais uniquement dans le contexte d'une véritable collection clé / valeur telle qu'un dictionnaire. Pour tout ce qui consiste en un nombre variable de types, ils ajoutent un nombre. Voici un autre exemple: msdn.microsoft.com/en-us/library/dd402872(v=vs.110).aspx
Pete
1
Eh bien, vos modifications obsolètes certains des commentaires. :) Pourquoi ne pouvez-vous pas simplement conserver les classes dans le même fichier physique? S'ils sont si différents que vous devez les conserver dans des fichiers séparés, pouvez-vous nous dire ce qui les rend différents?
Pete

Réponses:

14
MyGenericClass`1.cs
MyGenericClass`2.cs
MyGenericClass`3.cs

Et ainsi de suite, où le nombre après le backtick est le nombre de paramètres de type générique. Cette convention est utilisée par Microsoft.

Alternativement, vous pouvez utiliser quelque chose comme

MyGenericCollectionClass[TKey, TValue].cs

qui conserve non seulement le nombre de paramètres de type génériques, mais aussi leurs noms spécifiques. Certes, cela ne préserve pas les équerres, mais nous ne pouvons pas avoir tout ce que nous voulons dans la vie, n'est-ce pas?

Robert Harvey
la source
1
Le compilateur modifie en interne le nom des types génériques, en ajoutant un backtick et le nombre de paramètres génériques car .NET n'autorise pas plusieurs types avec le même nom avec un nombre différent de paramètres génériques mais C # le permet. La convention de dénomination des fichiers correspond donc à ce que fait le compilateur.
CodesInChaos
1
Je voulais vous prouver le contraire, mais en fait vous avez raison: github.com/dotnet/corefx/tree/master/src/… Je n'aime pas cette convention.
Den
1
@Den, il semble que maintenant ils ont regretté cette convention. Peut-être que cela impliquait un problème? github.com/dotnet/corefx/commit/…
Sam
@Sam Espérons que ce ne soit pas un problème de communication entre les équipes Microsoft. Parce que personne d'autre ne le fait. C'est aussi à l'équipe du compilateur, et non à l'équipe de la bibliothèque, de décider à mon avis.
Den
Je n'aurais pas les boules d'utiliser "" "dans un nom de fichier.
Cristian E.
4

Dans le cas de Tupleet Actionque Pete a mentionné, Microsoft utilise lui-même un seul fichier - voir Tuple.cs et Action.cs .

Je pense que cela dépend en partie du fait que la fonctionnalité de toutes les classes soit ou non la même. Personnellement, je n'aime pas regrouper les classes dans un seul fichier, mais cela pourrait être une exception. Dans le code source où je travaille, j'ai ajouté une génération automatique (en utilisant T4)NamedTuple qui agit de la même manière que Tuple, mais avec un nom de chaîne comme premier argument dans le constructeur.

Pour répondre à votre question, si vous ne souhaitez pas utiliser un seul fichier, utilisez peut-être MyClass_1.cs pour MyClass<T1>, MyClass_2.cs pour MyClass<T1, T2>, etc.

Aucune des deux options n'est cependant idéale, donc je serais enclin à suggérer l'argument "Microsoft fais comme ça, alors ...".

Wai Ha Lee
la source
2
Tupleet Actionsont tous des délégués; ils n'ont pas de code d'implémentation, donc mettre toutes les variations dans des fichiers séparés serait de toute façon inutile. Prouve simplement que chaque règle a une exception.
Robert Harvey
Ouais en général, mettre plusieurs délégués publics dans le même fichier est considéré comme correct (à condition qu'ils soient liés).
Stephen
1
@RobertHarvey, Tuplen'est pas un délégué, mais chaque implémentation est de toute façon courte.
Arturo Torres Sánchez
@ ArturoTorresSánchez: Oui, je pensais Func.
Robert Harvey
0

Vous êtes-vous demandé si les cours ont vraiment la même intention? Si une classe est plus générique que l'autre, alors ce sera un GenericClass , un MoreGenericClass et un MostGenericClass . Imaginez que chaque paramètre de type d'une classe ajoute une nouvelle dimension à la classe, il peut donc être utile de demander de quelle dimension il s'agit.

Prenons cet exemple:

  • Container<Thing>
  • MetricContainer<Thing, Metric>
  • MetricTransportableContainer<Thing, Metric, Transport>

Je suis conscient que ce n'est pas le meilleur exemple, mais très expressif pour montrer trois dimensions:

  • Dimension intérieure, ce qu'il peut charger
  • métrique Dimension, avec laquelle la métrique peut être chargée, uniquement par nombre de choses ou par mesure carrée ou par capacité cubique ou par poids
  • Dimension extérieure, où il peut être chargé.

Vous pouvez donc modéliser le transport de voitures:

Container<Cars>
MetricContainer<Cars, CountMetric>
MetricTransportableContainer<Cars, CountMetric, Ship>

Transport de fluides:

Container<Fluid>
MetricContainer<Fluid, Volume>
MetricTransportableContainer<Fluid, Volume, Shelf>

Transport d'énergie:

Container<Energy>
MetricContainer<Energy, ElectricPower>
MetricTransportableContainer<Energy, ElectricPower, Box>

Transport de sucre, céréales:

Container<CrumblyMaterial>
MetricContainer<CrumblyMaterial, Weight>
MetricTransportableContainer<CrumblyMaterial, Weight, Silo>

Oh, quelle surprise: a List<T>a une dimension qui représente les choses que la liste peut contenir; et c'est un Map<T, S>à deux dimensions qui représentent les choses que la carte peut contenir et les clés d'accès.

shylynx
la source
1
Je ne pense pas que vous ayez compris la question. Regardez le dernier paragraphe de la question.
Robert Harvey
1
@RobertHarvey Veuillez lire attentivement la question: le nom de classe doit être équivalent au nom de fichier. C'est interchangeable. Le problème réside dans une mauvaise analyse de la classe et une mauvaise dénomination des classes génériques en général. Pour résumer ma réponse: "Nommez-le ce qu'il est et non ce qu'il semble être."
shylynx
1
@RobertHarvey Lisez ma réponse: Mettez une classe dans un fichier!
shylynx
1
Je pense que vous manquez le point. La question demande: Comment puis-je mettre Tuple<T1>, Tuple<T1, T2>et Tuple<T1, T2, T3>dans des fichiers CS séparés de manière standard, sans conflits de noms?
Robert Harvey