Question

    

Cette question a déjà une réponse ici:

         

J'ai des méthodes qui renvoient des collections privées à l'appelant et je veux empêcher ce dernier de modifier les collections renvoyées.

private readonly Foo[] foos;

public IEnumerable<Foo> GetFoos()
{
    return this.foos;
}

À l'heure actuelle, la collection privée est un tableau fixe, mais à l'avenir, la collection pourrait devenir une liste si le besoin d'ajouter de nouveaux éléments au moment de l'exécution se faisait sentir.

Il existe plusieurs solutions pour empêcher l'appelant de modifier la collection. Retourner IEnumerable<T> est la solution la plus simple, mais l'appelant peut toujours convertir la valeur de retour en IList<T> et modifier la collection.

((IList<Foo>)GetFoos())[0] = otherFoo;

Le clonage des collections présente l’inconvénient évident que deux collections peuvent évoluer indépendamment. Jusqu'à présent, j'ai envisagé les options suivantes.

  1. Emballage de la collection dans ReadOnlyCollection<T>.
  2. Renvoyer l'un des itérateurs LINQ définis par la classe Enumerable en effectuant une projection factice telle que list.Select(item => item). En fait, j’envisage d’utiliser Where(item => true) car l’itérateur renvoyé semble plus léger.
  3. Écriture d'un wrapper personnalisé.

Ce qui me déplaît dans l'utilisation de Add(), c'est qu'il implémente IList<T>.IsReadOnly et que l'appel de IList<T>.IsFixedSize ou l'accès à l'indexeur causera des exceptions. Bien que cela soit absolument correct en théorie, presque aucune vérification de code réelle MakeReadOnly() ou Skip(0).

L'utilisation des itérateurs LINQ - J'ai enveloppé le code dans une méthode d'extension <=> - empêche ce scénario, mais il a le goût d'un hack.

Écrire un wrapper personnalisé? Réinventer la roue?

Avez-vous des idées, des considérations ou d’autres solutions?

Tout en balisant cette question, j'ai découvert la question de débordement de pile . Je n'avais pas remarqué avant. Jon Skeet suggère d’utiliser le & "; LINQ hack &"; Aussi, mais encore plus efficace avec <=>.

Était-ce utile?

La solution

Malheureusement, il n’existe aucun moyen d’obtenir exactement ce que vous recherchez dans la version actuelle du cadre. Il n'a tout simplement aucun concept de collection indexable immuable / en lecture seule sur le type concret et le style d'interface.

Comme vous l'avez indiqué, ReadOnlyCollection<T> fonctionne correctement du côté du type de béton. Mais il n’existe pas d’interface correspondante à implémenter qui soit également en lecture statique.

Votre seul choix est de ...

  • Définissez votre propre classe de collection
  • Implémentez uniquement IEnumerable<T> ou définissez une interface en lecture seule nécessaire implémentée par votre collection.

Autres conseils

Pourquoi ne pas créer une copie complète de l’objet retourné? [Il n'y aura donc aucun effet sur la collection d'origine même si l'appelant décide de modifier la copie renvoyée]

List et Array ont une méthode AsReadOnly:

public IEnumerable<Foo> GetFoos()
{
    return Array.AsReadOnly(this.foos);
    // or if it is a List<T>
    // return this.foos.AsReadOnly();
}

Dans de tels cas, je crée une méthode dans la classe pour accéder aux éléments individuels de la collection privée. Vous pouvez également réaliser un indexeur ( http://msdn.microsoft.com/en- us / library / 6x16t2tx.aspx ) sur la classe contenant la collection privée.

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