views:

357

answers:

4

I have a class that contains a collection. I want to provided a method or property that returns the contents of the collection. It's ok if calling classes can modify the individual objects but I do not want them adding or removing object from the actual collection. I have been copying all the objects to a new list, but now I'm thinking that I could just return the list as IEnumerable<>.

In the simplified example below is GetListC the best way to return a read only version of a collection?

public class MyClass
{
    private List<string> mylist;

    public MyClass()
    {
        mylist = new List<string>();
    }

    public void Add(string toAdd)
    {
        mylist.Add(toAdd);
    }

    //Returns the list directly 
    public List<String> GetListA 
    { 
        get
            {
            return mylist;
            }
    }

    //returns a copy of the list
    public List<String> GetListB
    {
        get
        {
            List<string> returnList = new List<string>();

            foreach (string st in this.mylist)
            {
                returnList.Add(st);
            }
            return returnList;
        }
    }

    //Returns the list as IEnumerable
    public IEnumerable<string> GetListC
    {
        get 
        {
            return this.mylist.AsEnumerable<String>();
        }

    }

}
+1  A: 

Just use ReadOnlyCollection class, it is supported since .NET 2.0

nightcoder
+13  A: 

You can use List(T).AsReadOnly():

return this.mylist.AsReadOnly()

which will return a ReadOnlyCollection.

Joey
It's in the System.Collections.ObjectModel namespace.
GoodEnough
Huh, I'm surprised I messed that one.
Jonathan Allen
Of course you'll need to replace the return type from List<String> to ReadOnlyCollection<string> or ICollection<string> or IEnumrable<string>
Y Low
A: 

Use the generic ReadOnlyCollection class (Collection.AsReadOnly()). It doesn't copy any objects which may have some strange results when the underlying collection is changed.

        var foo = new List<int> { 3, 1, 2 };
        var bar = foo.AsReadOnly();

        foreach (var x in bar) Console.WriteLine(x);

        foo.Sort();

        foreach (var x in bar) Console.WriteLine(x);

But if you don't want a copy, that's the best solution.

Dario
A: 

I prefer returning IEnumerable, but you don't need to cast. Just do

public IEnumerable<string> StringList { get { return myList; }

List<string> is an IEnumerable<string>

Robert
The problem with that is it becomes very expensive to do things like determine the count.
Jonathan Allen
The real problem is that the consumer of the code can anytime cast it back to List<T> and modify the list.
Y Low
you don't always need the count, and the point is to expose an interface that gives you all the functionality you need, and none you don't
Robert