12
votes

Exposer correctement une liste ?

Je sais que je ne devrais pas expulser une liste code> dans une propriété, mais je me demande quelle est la bonne façon de le faire est? Par exemple, faire cela:

    public static IEnumerable<string> List
    {
        get
        {
            return new ReadOnlyCollection<string>(_list);
        }
    }


5 commentaires

Quel est le problème avec / exposant une liste (de T) en tant que propriété?


Vous ne pouvez pas l'étendre: blogs.msdn.com/fxcop/archive/2006/04/27/...


Je ne comprends pas quel est le point de ceci? Je veux dire, je voudrais simplement exposer la propriété comme la liste ... ??? Est-ce une question de fil-sécurité?


Pour que devez-vous l'étendre?


L'article donne un exemple: Si vous souhaitez déjà des notifications lorsque des éléments sont ajoutés / supprimés, vous ne pouvez pas le faire avec une liste, vous devez donc faire une nouvelle modification de votre interface publique. Également dans mon cas, il s'agissait d'une liste de lecture seule sans trop de frais généraux.


8 Réponses :


4
votes

Oui et Non. Oui, il existe une surcharge de performance, car un nouvel objet est créé. Non, votre liste n'est pas clonée, elle est enveloppée par le lononlycollection.


0 commentaires

2
votes

4 commentaires

asreadonly appelle simplement le constructeur lisonlycollection de la même manière que le code exemple de la question.


Je l'utiliserais toujours cependant. Le point principal est qu'il existe pour une raison quelconque et que le DOC pour cela passe de manière détaillée quant à ce qu'elle fait. Cela dit, non, ma réponse ne doit pas ajouter quelque chose que Marc n'est pas!


Était déchiré entre cela, Henrik et la réponse de Marc. En acceptant cela parce que je ne savais pas d'asReadonly (), car il est très concis, car il résout le problème, comme je peux le mettre en cache (création d'une statique privée listique lisonlycollection _listwrapper;, la configurant dans le constructeur, puis le renvoyer), et comme il semble être la bonne façon de le faire (j'ai vu Eric Lippert, le mentionner comme un bon moyen de l'envelopper). La sécurité du fil peut être un problème, mais c'est une question générale de toute façon.


Je suis honoré. Fair jeu pour le montant de la considération que vous avez mise au choix. Je suis sûr que je ne suis pas le seul ici avec un +1 pour la réponse perspicace de Marc pour Marc - Espérons que les points vont soulager la douleur de son frottement de vert! Merci!



8
votes

Exposer une liste code> comme une propriété n'est en réalité la racine de tout mal; Surtout si cela permet une utilisation attendue telle que foo.items.add (...) code>.

Vous pouvez écrire une alternative en cas de sécurité à Asenumerable () Code>:

        List<int> ints = new List<int> { 1, 2, 3 };
        var ro = ints.AsReadOnly();
        Console.WriteLine(ro.Count); // 3
        ints.Add(4);
        Console.WriteLine(ro.Count); // 4


4 commentaires

S / Exting / existant /: P (mais +1!)


J'oublie toujours que le rendement existe ... Sécurité des threads dans ASP.NET n'est pas une grande partie d'un problème que j'essaie de ne pas utiliser de classes statiques mutables dans ASP.NET car ils sont des demandes d'accrovage partagées. Je suppose que si je veux un "instantané", il n'y a aucun moyen d'une copie de toute façon, donc retour nouvelle liste (_ liste); "résoudre" cela, et si l'appelant le jette Retour à la liste Il ne modifie que sa propre copie mais pas la mienne. Le point principal est vraiment de conserver la classe1._list 'immuable' à des appelants extérieurs et exposez les fonctions ADD / Supprimer en classe1.


Oui, la copie complète protège contre tous les maux, à l'exception de certaines propriétés changeantes des objets dans la liste.


Stackoverflow.com/Questtions/1230293/...



2
votes

Vous n'avez pas besoin de vous inquiéter de la surcharge du clonage: Emballage d'une collection avec une collection ReadonlyCollection pas clone. Cela crée juste une enveloppe; Si la collection sous-jacente change, la version réadonnement change également.

Si vous craignez de créer des wrappers frais encore et encore, vous pouvez le mettre en cache dans une variable d'instance distincte.


0 commentaires

3
votes

Si la classe n'a pas d'autre objectif, vous pouvez hériter de la liste et remplacer la méthode d'ajout et le faire lancer une exception.


3 commentaires

Vous devriez hériter de Collection pour faire cela ... Liste n'a pas beaucoup virtuel membres.


Mais ce serait une violation du LSP, mais une "idée de hack" intéressante néanmoins.


Cela peut être une option, il suffit de «se sentir faux» car je pense que le cadre doit déjà fournir un mécanisme approprié hors de la boîte.



0
votes

Asenumerable et Readonlycollection ont un problème lorsque votre énumération est à mi-chemin et la collecte est modifiée. Ces choses ne sont pas en sécurité. Les retournant comme une matrice et la mettre en cache au moment de l'appel peut être une option bien meilleure.

Par exemple, P>

public static String[] List{
   get{
      return _List.ToArray();
   }
} 

//While using ...

String[] values = Class1.List;

foreach(string v in values){
  ...
}

// instead of calling foreach(string v in Class1.List)
// again and again, values in this context will not be
// duplicated, however values are cached instance so 
// immediate changes will not be available, but its
// thread safe
foreach(string v in values){
  ...
}


3 commentaires

Les tableaux en classe publique sont considérés comme mauvaises pratiques


Pas toujours, mais Eric Lippert a eu quelques pensées à ce sujet: blogs.msdn.com/ericlippert/archive/2008/09/22/...


@Przemaas, il n'y a pas de règle générale comme des matrices de mauvaises pratiques, sa situation toujours dépendante, si vous démontez et regardez la source de la liste, il dispose d'un tableau pour stocker également ses propres objets. Lorsque vous ne souhaitez pas modifier le contenu et que vous avez besoin de la seule collection, une matrice est le seul moyen le plus rapide de le faire.



1
votes

Si vous exposez votre liste comme IEnumerable, je ne m'inquiéterais pas des appelants qui jettent la liste. Vous avez explicitement indiqué dans le contrat de votre classe que seules les opérations définies dans IEnumérables sont autorisées sur cette liste. Vous avez donc implicitement indiqué que la mise en œuvre de cette liste pourrait changer à peu près tout ce qui implémente iEnumerable.


1 commentaires

C'est vrai, et comme Svish a souligné que c'est (près?) Impossible de le faire de toute façon sans copier profondément les données, mais je voulais avoir une petite barrière pour empêcher les gens de se tirer trop facilement dans le pied.



2
votes

J'ai posé une question similaire plus tôt:


0 commentaires