1

I have a field of type ICollection<T>. Is there a simple way to make it read only?

Note, the ReadOnlyCollection<T> class takes an IList<T>, I'm looking for a way to invert an ICollection<T> and ensure user cannot alter the collection.

Using AsEnumerable ex. method, won't guarantee that, since it could be casted back to its original type, which could also be List.

Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
  • If you are happy with a copy of the original collection -- i.e. returning an object that won't reflect future changes to the original collection -- then IMHO it is fine to just copy the collection to an array and return that (wrapping in ReadOnlyCollection if you really want to, but it's probably not strictly necessary at that point). If you do want the returned collection to reflect future changes to the original, then see my posted answer. – Peter Duniho Oct 21 '14 at 00:57

2 Answers2

1

I've always thought it a little odd that ReadOnlyCollection<T> is really a read-only list.

That said, ICollection<T> is such a simple interface, it's trivial to implement a true ReadOnlyCollection<T>:

public class TrueReadOnlyCollection<T> : ICollection<T>, IReadOnlyCollection<T>
{
    private ICollection<T> _original;

    public TrueReadOnlyCollection(ICollection<T> original)
    {
        _original = original;
    }

    public void Add(T item)
    {
        throw new NotSupportedException();
    }

    public void Clear()
    {
        throw new NotSupportedException();
    }

    public bool Contains(T item)
    {
        return _original.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _original.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return _original.Count; }
    }

    public bool IsReadOnly
    {
        get { return true; }
    }

    public bool Remove(T item)
    {
        throw new NotSupportedException();
    }

    public IEnumerator<T> GetEnumerator()
    {
        foreach (T t in _original)
        {
            yield return t;
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Note that with .NET 4.5 there are also actual read-only interfaces to support the newish interface-variance features, so if you're doing the above it might be nice to also implement IReadOnlyCollection<T>

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
1

ICollection implements IEnumerable, so i think you could just do .ToList().AsReadOnly(). But as noted by Peter Duniho, this creates a copy of the original collection, so any changes to it will not be represented in the copy, although it seems like this is probably what you want.

peterjb
  • 819
  • 7
  • 6
  • As you note this creates an extra copy of everything, which can be a major issue for large collections. – Eric J. Oct 21 '14 at 01:13