views:

108

answers:

2

I have a class which contains a List<Item> I have a getter on the class that returns this. Is there some thing I can do to ensure the user who calls cannot modify the returned List? (Since it's a reference type - I believe changes to the returned reference would affect the list stored in the source object)

+5  A: 

Return your List wrapped in ReadOnlyCollection<T>.

  public ReadOnlyCollection<Item> MyROList {
    get { return new ReadOnlyCollection<Item>(myList); }
  }

  private List<Item> myList = new List<Item>();

More details elsewhere on SO.

Depending on usage of your class, you could allocate the ReadOnlyCollection at construction time and link it to the underlying List. If you expect to always or most of the time need this property, and the underlying List is in place at that time, then this is sensible. Otherwise you could leave the ReadOnlyCollection<Item> class member null and allocate it on demand in the getter if it is null (taking thread safety into account).

Steve Townsend
Thanks for the answer. Wouldn't it be better to wrap the collection in a ReadOnlyCollection in the constructor - so that its done just once, rather than doing it each time. Of course my object is a bit heavier - since I have an extra member. But probably better than creating new objects each time?
aip.cd.aish
@Steve ReadOnlyCollection is a live copy of the source collection. When the source collection changes, the ReadOnlyCollection changes too.
TheFogger
@TheFogger - thanks for correction, post edited
Steve Townsend
+2  A: 

Do you want any changes your class makes in the future to be reflected in the returned list? If so, simply

return new ReadOnlyCollection<T>(list);

would be fine.

However, if you want to return a collection which nothing will modify in the future (i.e. a completely independent copy of the original list) you might want to use:

return new ReadOnlyCollection<T>(list.ToList());

(Using LINQ's ToList method is a very simple way of cloning a list.)

Note that if the list's element type is a mutable reference type, changes to the data within the referenced objects would still be visible to everyone, of course.

Jon Skeet
`list.AsReadOnly()` / `list.ToList().AsReadOnly()` are terse alternatives for `List<T>`. For a general `IList<T>`, the constructor for `ReadOnlyCollection<T>` is probably the best option.
Ani
+1 Thanks for the example. It's good to know ToList can be used to clone a list.
aip.cd.aish
+1 @Ani. Thats awesome, didn't know that.
aip.cd.aish
@Jon: Wouldn't it be better to wrap the collection in a ReadOnlyCollection in the constructor - so that its done just once, rather than doing it each time. Of course my object is a bit heavier - since I have an extra member. But probably better than creating new objects each time? Thanks for the answer.
aip.cd.aish
@Ani: I think it's good to return a `ReadOnlyCollection<T>` - and make that explicit in the API - to make it absolutely clear that the caller can't add items to it. It would be nice if there were an interface representing a read-only list, but there isn't :(
Jon Skeet
@aip.cd.aish: It's a pretty light-weight object, but it depends on how often it's going to be called, I guess. It feels a little odd to have another field for this, but in some cases it *could* make sense, yes.
Jon Skeet
@Jon Skeet: Don't understand your point; `List<T>.AsReadOnly()` creates and returns a `new ReadOnlyCollection<T>.` Its return type is `ReadOnlyCollection<T>`, not `IList<T>`, so no casting is required to "make that explicit in the API." Or have I misunderstood? I do agree about the lack of an interface for read-only collections though.
Ani
@Ani: Ah, I missed that. Yes, in that case that's fine :)
Jon Skeet
@Jon: I just realized what you meant in your last sentence! That is a very good point. Did not realize that. The object that is accessed through the readonly list is still modifiable.
aip.cd.aish
@aip.cd.aish: Just remember that the list doesn't contain objects - it contains *references*. .NET doesn't have the idea of a "read-only reference to a mutable object" or anything really similar.
Jon Skeet