Question

J'ai un objet dans un environnement multi-thread qui gère une collection d'informations, par exemple:

public IList<string> Data 
{
    get 
    {
        return data;
    }
}

J'ai actuellement return data; enveloppé par un ReaderWriterLockSlim pour protéger la collecte de violations de partage.Cependant, pour être doublement sûr, j'aimerais revenir à la collection en lecture seule, de sorte que le code appelant est incapable d'apporter des modifications à la collecte, à la seule vue de ce qui est déjà là.Est-ce possible?

Était-ce utile?

La solution

Si votre seul but est d'obtenir le code appelant à ne pas faire une erreur, et modifier la collection quand il ne devrait être que la lecture de tout ce qui est nécessaire est de retour d'une interface qui ne supporte pas les Ajouter, Supprimer, etc..Pourquoi pas le retour IEnumerable<string>?Code d'appel aurait à cast, qu'ils sont peu susceptibles de faire sans le savoir à l'intérieur de la propriété, ils ont accès.

Cependant, si votre but est d'empêcher le code d'appel à partir de l'observation des mises à jour à partir d'autres threads, vous aurez à revenir à des solutions déjà mentionné, pour effectuer une profonde ou peu profonde copie en fonction de votre besoin.

Autres conseils

Si votre sous-tendent les données sont stockées sous forme de liste, vous pouvez utiliser Liste(T).AsReadOnly la méthode.
Si vos données peuvent être énumérés, vous pouvez utiliser Énumérable.ToList méthode pour lancer votre collecte de Liste et appeler AsReadOnly sur elle.

J'ai voté pour votre réponse et en accord avec elle-mais pourrais-je vous donner quelque chose à considérer?

Ne pas renvoyer une collection directement.Faire un avec exactitude nommé logique de classes, qui reflète l'objectif de la collection.

Le principal avantage de cela est le fait que vous ne pouvez pas ajouter de code, des collections et donc à chaque fois que vous avez un natif de "collection" dans l'objet de votre modèle, vous avez TOUJOURS la non-OO code de support, réparties tout au long de votre projet pour y accéder.

Par exemple, si votre collection est factures, vous auriez probablement 3 ou 4 endroits dans votre code où vous itéré des factures impayées.Vous pourriez avoir un getUnpaidInvoices méthode.Cependant, le vrai pouvoir vient quand vous commencez à penser à des méthodes comme le "payUnpaidInvoices(payeur, compte);".

Lorsque vous passez autour des collections à la place de l'écriture d'un objet modèle, des classes entières de refactorings n'arrivera jamais à vous.

Notez également que ce qui rend votre problème particulièrement agréable.Si vous ne voulez pas que les gens de changer les collections, votre conteneur doivent contenir aucun des mutateurs.Si vous décidez plus tard que dans un seul cas, vous devez le modifier, vous pouvez créer un mécanisme de sécurité à le faire.

Comment voulez-vous résoudre ce problème lorsque vous êtes de passage autour d'un natif de la collection?

Aussi, natif des collections ne peut pas être améliorée avec des données supplémentaires.Vous reconnaîtrez ce la prochaine fois que vous trouvez que vous passez dans la Collection, en sus) à plus d'une ou deux méthodes.Il indique que "Extra" appartient à l'objet contenant votre collection.

Je pense que vous êtes à la confusion des concepts ici.

L' ReadOnlyCollection fournit un wrapper en lecture seule pour une collection existante, vous permettant de vous (Classe A) pour passer d'une référence à la collection de coffre-fort à la connaissance que l'appelant (Classe B) ne pas modifier la collection (c'est à direne peut pas ajouter ou supprimer les éléments de la collection.)

Il n'y a absolument pas de fil-de garanties de sécurité.

  • Si vous (Classe A) de continuer à modifier la collection sous-jacente après vous la main comme une ReadOnlyCollection puis la classe B va voir ces changements, toutes les itérateurs invalidé, etc.et généralement être ouvert à tout de l'habitude des problèmes de concurrence avec les collections.
  • En outre, si les éléments de la collection sont mutables, vous (Classe A) et l'appelant (Classe B) sera en mesure de changer tout mutable état des objets de la collection.

Votre mise en œuvre dépend de vos besoins:- Si vous n'avez pas de soins sur l'appelant (Classe B), de voir d'autres modifications à la collection, alors vous pouvez simplement clone de la collecte, de la main, et cesser de s'inquiéter.- Si vous avez absolument besoin de l'appelant (Classe B) pour voir les modifications apportées à la collecte, et vous voulez que ce soit thread-safe, alors vous avez plus d'un problème sur vos mains.Une possibilité est de mettre en place votre propre thread-safe variante de la ReadOnlyCollection pour permettre verrouillé l'accès, mais ce sera non négligeable et non-performant si vous voulez soutenir IEnumerable, et il encore ne sera pas vous protéger contre les mutable éléments dans la collection.

Il convient de noter que aku's réponse protège uniquement la liste comme étant en lecture seule.Les éléments de la liste sont toujours très accessible en écriture.Je ne sais pas si il existe un moyen de protéger les non-atomique des éléments sans clonage eux avant de les placer dans la lecture seule liste.

Vous souhaitez utiliser la rendement mot-clé.Vous parcourez la IEnumerable liste et retourner les résultats avec le rendement.Cela permet au consommateur d'utiliser le pour chacun, sans modification de la collecte.

Il ressemblerait à quelque chose comme ceci:

List<string> _Data;
public IEnumerable<string> Data
{
  get
  {
    foreach(string item in _Data)
    {
      return yield item;
    }
  }
}

Vous pouvez utiliser une copie de la collection à la place.

public IList<string> Data {
get {
    return new List<T>(data);
}}

De cette façon, il n'a pas d'importance si il est mis à jour.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top