Question

This question already has an answer here:

I have methods returning private collections to the caller and I want to prevent the caller from modifying the returned collections.

private readonly Foo[] foos;

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

At the moment the private collection is a fixed array, but in the future the collection might become a list if the need for adding new items at run time arises.

There are several solutions to prevent the caller from modifying the collection. Returning IEnumerable<T> is the simplest solution, but the caller can still up-cast the return value to IList<T> and modify the collection.

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

Cloning the collections has the obvious disadvantage that there are two collections that can evolve independently. So far I have considered the following options.

  1. Wrapping the collection in ReadOnlyCollection<T>.
  2. Returning one of the LINQ iterators defined by the Enumerable class by performing a dummy projection like list.Select(item => item). Actually I consider using Where(item => true) because the returned iterator seems more lightweight.
  3. Writing a custom wrapper.

What I don't like about using ReadOnlyCollection<T> is that it implements IList<T> and calling Add() or accessing the indexer will cause exceptions. While this is absolutly correct in theory, almost no real code checks IList<T>.IsReadOnly or IList<T>.IsFixedSize.

Using the LINQ iterators - I wrapped the code in an extension method MakeReadOnly() - prevents this scenario, but it has the taste of a hack.

Writing a custom wrapper? Reinventing the wheel?

Any thoughts, considerations, or other solutions?


While tagging this question, I discovered this Stack Overflow question I didn't notice before. Jon Skeet suggest to use the "LINQ hack", too, but even more efficient using Skip(0).

Was it helpful?

Solution

Unfortunately there is no way to achieve exactly what you are looking for in the current version of the framework. It simply has no concept of an indexable immutable / read-only collection on both the concrete type and interface style.

As you pointed out, ReadOnlyCollection<T> works OK on the concrete type side. But there is no corresponding interface to implement which is also statically read-only.

You're only real choice is to ...

  • Define your own collection class
  • Either only implement IEnumerable<T> or define a need read-only interface which your collection implements.

OTHER TIPS

How about making a deep copy of the object being returned? [So there will be no effect on the original collection even if the caller decides to make changes to the copy returned]

List and Array have a AsReadOnly method :

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

In such cases i create a methods insde the class to access individual elements of the private collection. You also can realize indexer (http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx) on the class that contains private collection.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top