LWChris LWChris - 5 months ago 30
C# Question

How to turn ICollection<T> into IReadOnlyCollection<T>?

When I have a variable of

in C#, I cannot pass it to a function that expects an

public void Foo()
ICollection<int> data = new List<int>();
// Bar(data); // Not allowed: Cannot implicitly cast ICollection<int> to IReadOnlyCollection<int>
Bar(data.ToList()); // Works, since List<T> implements IReadOnlyCollection<T>

public void Bar(IReadOnlyCollection<int> data)
if (data.Count == 1) { /* ... */ }
// ...

Apparently the problem is that
does not inherit from
- but why?
should be the full functional set of
plus the functions that modify the collection.

And what is the best solution to pass the arguments?

On the one hand, since I don't want to alter the collection in
and just need the count and iterate over the collection, I'd like to require an

On the other hand, I don't want to create a new list object every time I call that function.


There is no standard solution AFAIK, but it's not hard to make your own like this

public static class MyExtensions
    public static IReadOnlyCollection<T> AsReadOnly<T>(this ICollection<T> source)
        if (source == null) throw new ArgumentNullException("source");
        return source as IReadOnlyCollection<T> ?? new ReadOnlyCollectionAdapter<T>(source);
    sealed class ReadOnlyCollectionAdapter<T> : IReadOnlyCollection<T>
        ICollection<T> source;
        public ReadOnlyCollectionAdapter(ICollection<T> source) { this.source = source; }
        public int Count { get { return source.Count; } }
        public IEnumerator<T> GetEnumerator() { return source.GetEnumerator(); }
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

And then use it as follows