web-dev-qa-db-fra.com

IEnumerable to IReadOnlyCollection

J'ai IEnumerable<Object> et ai besoin de passer à une méthode en tant que paramètre mais cette méthode prend IReadOnlyCollection<Object>

Est-il possible de convertir IEnumerable<Object> en IReadOnlyCollection<Object>?

20
Mohamed Badr

Une solution serait de construire une liste et d’appeler AsReadOnly() dessus:

IReadOnlyCollection<Object> rdOnly = orig.ToList().AsReadOnly();

Ceci produit ReadOnlyCollection<object> , qui implémente IReadOnlyCollection<Object>.

Remarque: Puisque List<T> implémente également IReadOnlyCollection<T>, l'appel à AsReadOnly() est facultatif. Bien qu'il soit possible d'appeler votre méthode avec le résultat de ToList(), je préfère utiliser AsReadOnly() pour que les lecteurs de mon code voient que la méthode que j'appelle n'a pas l'intention de modifier ma liste. Bien sûr, ils pourraient découvrir la même chose en regardant la signature de la méthode que j'appelle, mais il est agréable d'être explicite à ce sujet.

24
dasblinkenlight

En guise d'alternative à la réponse de dasblinkenlight, pour éviter que l'appelant passe à la liste List <T> , au lieu de orig.ToList().AsReadOnly(), il pourrait être préférable de:

ReadOnlyCollection<object> rdOnly = Array.AsReadOnly(orig.ToArray());

C'est le même nombre d'appels de méthode, mais l'un prend l'autre comme paramètre au lieu d'être appelé sur la valeur de retour.

1
Neo

Puisque les autres réponses semblent aller dans le sens d'envelopper les collections dans un type {vraiment} en lecture seule, laissez-moi ajouter ceci.

J'ai rarement vu, voire jamais, une situation dans laquelle l'appelant est si effrayé qu'une méthode de prise de IEnumerable<T> pourrait essayer de transformer de manière malveillante ce IEnumerable<T> en une variable List ou un autre type mutable et commencer à le muter. Musique d'attente en file d'attente et rire diabolique!

Non. Si le code que vous utilisez est même raisonnable à distance, s'il demande un type doté uniquement d'une fonctionnalité de lecture (IEnumerable<T>, IReadOnlyCollection<T>...), il ne fera que lire.

Utilisez ToList() et en finir.

En remarque, si vous créez la méthode en question, il est généralement préférable de ne demander qu'un IEnumerable<T>, indiquant que vous voulez simplement "lire un tas d'éléments". Que vous ayez ou non besoin de sa Count ou de l'énumérer plusieurs fois est un détail de la mise en œuvre et est certainement sujet à changement. Si vous avez besoin de plusieurs énumérations, procédez comme suit:

items = items as IReadOnlyCollection<T> ?? items.ToList(); // Avoid multiple enumeration

Ceci garde la responsabilité à laquelle elle appartient (aussi localement que possible) et la signature de la méthode propre.

Lorsque retour un groupe d'éléments, par contre, je préfère renvoyer un IReadOnlyCollection<T>. Pourquoi? Le but est de donner à l'appelant quelque chose qui réponde à des attentes raisonnables - ni plus, ni moins. Ces attentes sont généralement que la collection est matérialisée et que la Count est connue - précisément ce que IReadOnlyCollection<T> fournit (et un simple IEnumerable<T> ne le permet pas). Sans être plus spécifique que cela, notre contrat correspond aux attentes et la méthode reste libre de modifier la collection sous-jacente. (En revanche, si une méthode retourne un List<T>, je me demande quel est le contexte dans lequel je devrais vouloir indexer dans la liste et la muter ... et la réponse est généralement "none".)

0
Timo