6
votes

Y a-t-il des inconvénients pour créer une classe qui encapsule une collection générique?

Une partie de mon application (C # 3.0 .NET 3.5) nécessite que plusieurs listes de chaînes soient maintenues. Je les déclare, sans surprise, comme list et tout fonctionne, ce qui est agréable.

Les chaînes de ces list s sont en réalité (et toujours). . Je me demande si cela pourrait être plus d'intention - révélateur d'être plus explicite, par exemple: xxx

... et cela fonctionne aussi. Y a-t-il des inconvénients évidents à cela, techniquement ou philosophiquement?


1 commentaires

Il est dangereux en C ++, mais parfaitement bien en C #.


5 Réponses :


2
votes

Personnellement, je le laisserais comme une liste list ou éventuellement créer un fondidide Classe qui envoie une chaîne puis stocke une liste .

La liste L'option appliquerait le type de type et vous permettrait de mettre une certaine validation sur fondidés . .


1 commentaires

En réalité, la classe String est scellée, ce qui découle de cela ne serait pas possible.



7
votes

Je commencerais en allant dans l'autre direction: Enroulant la chaîne dans une classe / structure appelée fondidid. L'avantage de le faire, je pense, est supérieur à la liste générique par rapport à la liste spécialisée.

  1. Votre code devient Type-Safe: Il y a beaucoup moins de possibilités de transmettre une chaîne représentant quelque chose d'autre dans une méthode qui s'attend à un identifiant de fonds.
  2. Vous pouvez contraindre les chaînes valides dans le constructeur pour fondidid, c'est-à-dire appliquer une longueur maximale, vérifiez que le code est dans le format attendu, etc.
  3. Vous avez un endroit pour ajouter des méthodes / fonctions relatifs à ce type. Par exemple, si les codes de fonds commençant «I» sont des fonds internes, vous pouvez ajouter une propriété appelée Isinternal qui formelle cela.

    Quant à la FundidList, l'avantage de disposer d'une telle classe est similaire au point 3 ci-dessus pour le FUDIDID: vous avez un endroit où vous devez accroître les méthodes / fonctions qui fonctionnent sur la liste des Fundids (c'est-à-dire des fonctions agrégées). Sans un tel endroit, vous constaterez que les méthodes d'assistance statique commencent à se détacher tout au long du code ou, dans une classe d'assistance statique.


1 commentaires

Certainement la voie à suivre. Spécialisez le type d'élément, car cette spécialisation des besoins (pour un fondidide ), mais la liste (dans votre cas) est une liste et reste comme une liste. Il suffit de dériver de (et de spécialiser) si vous avez vraiment besoin d'une nouvelle fonctionnalité de la liste elle-même (qui ne peut pas être résolue par une autre classe de collecte ou LINQ).



3
votes

Liste <> n'a pas de membres virtuels ou protégés - ces classes doivent presque jamais sous-classées. En outre, bien que cela soit possible, vous avez besoin de la fonctionnalité complète de Liste , si vous le faites - est-ce qu'il y a beaucoup de point pour faire une telle sous-classement?

Le sous-classement a une variété de descentes. Si vous déclarez que votre type local soit fondidlist , vous ne pourrez pas l'affecter par ex. Utilisation de Linq et .tolist Étant donné que votre type est plus précis. J'ai vu des gens décider qu'ils ont besoin de fonctionnalités supplémentaires dans de telles listes, puis l'ajoutent à la classe de liste sous-classée. C'est problématique, car la mise en œuvre de la liste ignore de tels bits supplémentaires et peut violer vos contraintes - par exemple. Si vous exigez l'unicité et déclarez une nouvelle méthode d'ajout, quiconque qui est simplement (légalement) à Liste par exemple en transmettant la liste sous forme de paramètre saisi comme tel utilisera la liste par défaut Ajouter, non votre nouvel ajouter. Vous ne pouvez ajouter que des fonctionnalités, ne jamais le supprimer - et il n'y a pas de membres protégés ou virtuels nécessitant un sous-classement à exploiter.

Vous ne pouvez donc pas réellement ajouter de fonctionnalité que vous ne pouviez pas avec une méthode d'extension, et vos types ne sont plus compatibles qui limitent ce que vous pouvez faire avec votre liste.

Je préfère déclarer une structure fondidide contenant une chaîne et implémenter toutes les garanties concernant cette chaîne dont vous avez besoin, puis travailler avec une liste plutôt qu'un < Code> Liste .

enfin, voulez-vous vraiment dire Liste <> ? Je vois beaucoup de gens utilisent Liste <> pour les choses pour lesquelles iEnumerable <> ou des tableaux simples sont plus appropriés. Exposer votre liste interne dans une API est particulièrement délicate car cela signifie que tout utilisateur d'API peut ajouter / supprimer / modifier des éléments. Même si vous copiez votre liste d'abord, une telle valeur de retour est toujours trompeuse, car les gens peuvent attendre pour pouvoir ajouter / supprimer / changer d'éléments. Et si vous êtes pas exposant la liste dans une API, mais simplement l'utiliser pour la comptabilité interne, ce n'est pas aussi intéressant de déclarer et d'utiliser un type qui n'ajoute aucune fonctionnalité , seule la documentation.

Conclusion

Utilisez uniquement la liste <> pour internals et ne le sous-classez pas si vous le faites. Si vous souhaitez une sécurité explicite, enveloppez chaîne dans une structure (pas une classe, puisque une structure est plus efficace ici et a une meilleure sémantique: il n'y a pas de confusion entre un null fondidé et une chaîne NULL, ainsi que l'égalité d'objet et le scellage de hashcode comme prévu avec les structures mais doivent être spécifiés manuellement pour les classes). Enfin, exposez iEnumerable <> si vous devez prendre en charge l'énumération ou si vous avez besoin d'indexation aussi bien, utilisez le simple Readonlycollection <> wrapper autour de votre liste plutôt que de laisser le client API avec des bits internes. Si vous vraiment besoin d'une API de liste mutatitable, Observablecollection <> au moins vous permet de réagir aux modifications du client.


0 commentaires

1
votes

juste laissez-le comme une liste code>, votre nom de variable est suffisant pour dire aux autres qu'il stocke des fondidés.

public class FundIdList : List<string> 
{
   public void SpecialAction()
   {
      //can only do with a fund id list
      //sorry I can't give an example :(
   }
}


3 commentaires

Quelle que soit la spécialité, cela pourrait être une méthode d'extension.


@Amon: Parfois, il ne veut pas que la méthode appelée par une liste .


Que voulez-vous dire - appelé par?



0
votes

sauf si je voulais que quelqu'un fasse tout ce qu'ils pouvaient à List , sans aucune intervention de la partie de Fundidlist Je préférerais mettre en œuvre Ilist (ou une interface supérieure à la hiérarchie si je ne me souciais pas de la plupart des membres de cette interface) et de déléguer des appels à une liste privée le cas échéant.

Et si je voulais que quelqu'un ait ce degré de contrôle, je leur donnerais probablement juste une liste en premier lieu. Vous avez probablement quelque chose pour vous assurer que de telles chaînes sont réellement «ID de fonds», que vous ne pouvez plus garantir que vous utilisez publiquement l'héritage.

En réalité, cela sonne (et fait souvent avec liste ) comme un cas naturel pour héritage privé. Hélas, C # n'a pas d'héritage privé, la composition est donc la voie à suivre.


0 commentaires