IEnumerable to IReadOnlyCollection

21,571

Solution 1

One way would be to construct a list, and call AsReadOnly() on it:

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

This produces ReadOnlyCollection<object>, which implements IReadOnlyCollection<Object>.

Note: Since List<T> implements IReadOnlyCollection<T> as well, the call to AsReadOnly() is optional. Although it is possible to call your method with the result of ToList(), I prefer using AsReadOnly(), so that the readers of my code would see that the method that I am calling has no intention to modify my list. Of course they could find out the same thing by looking at the signature of the method that I am calling, but it is nice to be explicit about it.

Solution 2

Since the other answers seem to steer in the direction of wrapping the collections in a truly read-only type, let me add this.

I have rarely, if ever, seen a situation where the caller is so scared that an IEnumerable<T>-taking method might maliciously try to cast that IEnumerable<T> back to a List or other mutable type, and start mutating it. Cue organ music and evil laughter!

No. If the code you are working with is even remotely reasonable, then if it asks for a type that only has read functionality (IEnumerable<T>, IReadOnlyCollection<T>...), it will only read.

Use ToList() and be done with it.

As a side note, if you are creating the method in question, it is generally best to ask for no more than an IEnumerable<T>, indicating that you "just want a bunch of items to read". Whether or not you need its Count or need to enumerate it multiple times is an implementation detail, and is certainly prone to change. If you need multiple enumeration, simply do this:

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

This keeps the responsibility where it belongs (as locally as possible) and the method signature clean.

When returning a bunch of items, on the other hand, I prefer to return an IReadOnlyCollection<T>. Why? The goal is to give the caller something that fulfills reasonsable expectations - no more, no less. Those expectations are usually that the collection is materialized and that the Count is known - precisely what IReadOnlyCollection<T> provides (and a simple IEnumerable<T> does not). By being no more specific than this, our contract matches expectations, and the method is still free to change the underlying collection. (In contrast, if a method returns a List<T>, it makes me wonder what context there is that I should want to index into the list and mutate it... and the answer is usually "none".)

Solution 3

As an alternative to dasblinkenlight's answer, to prevent the caller casting to List<T>, instead of doing orig.ToList().AsReadOnly(), the following might be better:

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

It's the same number of method calls, but one takes the other as a parameter instead of being called on the return value.

Share:
21,571

Related videos on Youtube

Mohamed Badr
Author by

Mohamed Badr

Developer who like coding,coding and coding. for me programming is a life not only way to earn living best moments ever for me starting new service or web application

Updated on August 01, 2022

Comments

  • Mohamed Badr
    Mohamed Badr almost 2 years

    I have IEnumerable<Object> and need to pass to a method as a parameter but this method takes IReadOnlyCollection<Object>

    Is it possible to convert IEnumerable<Object> to IReadOnlyCollection<Object> ?

  • Scott Chamberlain
    Scott Chamberlain over 8 years
    .AsReadOnly() does have its uses. If you just return List<T> someone can do a rdOnly is IList<T> and it will return true, if you do .AsReadOnly() it will return false. If I don't know if my consumer could potentially try to cast my result in to a mutable interface I often do a .AsReadOnly() before I return the result.
  • florien
    florien over 5 years
    @ScottChamberlain this is a very important security feature to mention!
  • florien
    florien over 5 years
    This might even be faster!
  • Soner from The Ottoman Empire
    Soner from The Ottoman Empire over 4 years
    @florien why might it even faster? Could you explain?
  • florien
    florien over 4 years
    @snr Well, to be honest, I could not back it with a reasonable explanation. Somehow I believe that here, where the only difference is whether the type is first converted to an array or a list, arrays and working with them is more integrated into the language, and since the collection is not to be changed, list has no advantage here. Though it can indeed be that this all is optimised by the compiler.
  • Mass Dot Net
    Mass Dot Net over 3 years
    Could you call .ToArray() instead of .ToList().AsReadOnly() ?
  • Sergey Kalinichenko
    Sergey Kalinichenko over 3 years
    @MassDotNet You could, because arrays implement IReadOnlyCollection<T>.
  • Mass Dot Net
    Mass Dot Net over 3 years
    Thought so -- that's what I'm already doing. I just wanted to make sure there wasn't any errant behavior invited by doing so (e.g. screwing up sort order).
  • Benjamin Salerno
    Benjamin Salerno over 2 years
    Is there a way to do this the opposite? Convert IReadOnlyCollection to IEnumerable?
  • Sergey Kalinichenko
    Sergey Kalinichenko over 2 years
    @BenjaminSalerno IReadOnlyCollection<T> is an IEnumerable<T>, so you can plug it into any place where an IEnumerable<T> is needed.