6
votes

Comment autoriser l'itération sur une collection privée mais pas la modification?

Si j'ai le membre de classe suivant:

private List<object> obs;


0 commentaires

9 Réponses :


0
votes

Avez-vous envisagé de dériver une classe de System.Collections.ReadonlycollectionBase?


0 commentaires

14
votes

vous l'exposeriez sous forme d'un ienumerable , mais non seulement de le renvoyer directement: xxx

puisque vous avez indiqué que vous avez seulement voulu que vous vouliez que traverser Traversal < / em> de la liste, c'est tout ce dont vous avez besoin.

On pourrait être tenté de renvoyer la liste directement sous forme de ienumerable , mais ce serait incorrect, car on pourrait facilement inspecter le ienumerable au moment de l'exécution, il s'agit d'une liste et de le jeter à tel et Mutater le contenu.

Cependant, en utilisant retour obs.elect (o => o); Vous finissez par retourner un itérateur sur la liste , pas une référence directe à la liste elle-même.

Certains peuvent penser que cela qualifie comme une "expression dégénérée" selon la section 7.15.2.5 du C # Spécification de la langue. Cependant, Eric Lippert passe dans les détails sur la raison pour laquelle cette projection n'est pas optimisée .

En outre, les gens suggèrent que l'on utilise le Méthode d'extension asénumable . Ceci est incorrect, car l'identité de référence de la liste d'origine est maintenue. À partir de la section Remarques de la documentation:

Le asenumerable (iEnumerable ) Méthode n'a aucun effet autre que de modifier le type de source de compilation d'un Tapez qui implémente iEnumerable à ienumerable lui-même.

En d'autres termes, tout ce qu'il fait est de lancer le paramètre Source à IEnumerable , qui n'aide pas à protéger l'intégrité référenciale, la référence d'origine est renvoyée et peut être renvoyée à la liste et être utilisée pour muter la liste. < / p>


1 commentaires

Notez que nous n'utiliserions jamais un appel explicite appeler pour sélectionner si cela est apparu dans votre code. Nous optimiserions l'appel implicite pour sélectionner lors de la transformation d'une expression de requête en appels de méthode. Si vous dites "de x en y où sélectionnez x" Il n'y a pas d'appel Select, juste un endroit où. Mais si vous dites "de x en y Select x", nous ne générons pas simplement "y", nous génèverons un appel de sélection sur celui-ci pour assurer une immuabilité du résultat.




1
votes

Expose A Readonlycollection


2 commentaires

Ce n'est pas vraiment un problème de rendre le contacteur à faire une petite chasse. Le premier résultat sur Google rend évident comment exposer un Readonlycollection .


Je concéderai que ce que @Mitch Bheat aurait dû inclus un lien vers la page MSDN. De plus et nous serions simplement dupliquer le contenu de la page MSDN.



2
votes

Vous pouvez le faire de deux manières:

  1. soit en convertissant la liste en une collection lisonly: p>

    this.obs.AsEnumerable()
    
  2. ou en renvoyant un iEnumerable des éléments: p>

    new System.Collections.ObjectModel.ReadOnlyCollection<object>(this.obs)
    


0 commentaires


2
votes

à votre interface Ajoutez la méthode suivante Signature: Public Inumérable Traversethelist ()

implimenté comme suit: xxx

qui vous permettra de procéder à ce qui suit: xxx

Le rendement de rendement indique au compilateur de construire un énumérateur pour vous.


0 commentaires

3
votes

Cela a déjà été dit, mais je ne vois aucune des réponses comme étant superclear.

Le moyen le plus simple consiste simplement de retourner une liste de readonlycollection p> xxx pré>

L'inconvénient avec ceci est que si vous souhaitez modifier votre mise en œuvre plus tard, certains appelants peuvent déjà dépendre du fait que la collection fournit un accès aléatoire. Donc, une définition plus sûre serait de simplement exposer une note iEnumerable P>

public IEnumerable<object> Objs { 
    get { 
        return objs.AsEnumerable(); 
    } 
}


1 commentaires

Grande combinaison de simple + coffre-fort.



0
votes

Il suffit de renvoyer un iReadonlycollection code> .

private List<object> obs;

IReadOnlyCollection<object> GetObjects()
{
    return obs;
}


0 commentaires