views:

680

answers:

4

Following the suggestions of FxCop and my personal inclination I've been encouraging the team I'm coaching to use ReadOnlyCollections as much possible. If only so that recipients of the lists can't modify their content. In their theory this is bread & butter. The problem is that the List<> interface is much richer exposing all sorts of useful methods. Why did they make that choice?

Do you just give up and return writable collections? Do you return readonly collections and then wrap them in the writable variety? Ahhhhh.


Update: Thanks I'm familiar with the Framework Design Guideline and thats why the team is using FxCop to enforce it. However this team is living with VS 2005 (I know, I know) and so telling them that LINQ/Extension methods would solve their problems just makes them sad.

They've learned that List.FindAll() and .FindFirst() provide greater clarity than writing a foreach loop. Now I'm pushing them to use ReadOnlyCollections they lose that clarity.

Maybe there is a deeper design problem that I'm not spotting.

-- Sorry the original post should have mentioned the VS2005 restriction. I've lived with for so long that I just don't notice.

+3  A: 

Section 8.3.2 of the .NET Framework Design Guidelines Second Edition:

DO use ReadOnlyCollection<T>, a subclass of ReadOnlyCollection<T>, or in rare cases IEnumerable<T> for properties or return values representing read-only collections.

We go with ReadOnlyCollections to express our intent of the collection returned.

The List<T> methods you speak of were added in .NET 2.0 for convenience. In C# 3.0 / .NET 3.5, you can get all those methods back on ReadOnlyCollection<T> (or any IEnumerable<T>) using extension methods (and use LINQ operators as well), so I don't think there's any motivation for adding them natively to other types. The fact that they exist at all on List is just a historical note due to the presence of extension methods being available now but weren't in 2.0.

Jeff Moser
Sadly the team is stuck in the time warp of 2.0.
Mark Levison
+2  A: 

I don't have any insight as to why they weren't originally added. But now that we have LINQ I certainly see no reason to add them in future versions of the language. The methods you mentioned can easily be written in a LINQ query today. These days I just use the LINQ queries for pretty much everything. I actually more often get annoyed with List<T> having those methods because it conflicts with extension methods I write against IEnumerable<T>.

JaredPar
Sadly the team is stuck in the time warp of 2.0.
Mark Levison
@Mark, are you allowed to use VS2008 to compile C# 2.0 compatible code? If so, you can just define these extension methods yourself
JaredPar
Mark Levison
Mark Levison
+3  A: 

First off, ReadOnlyCollection<T> does implement IEnumerable<T> and IList<T>. With all of the extension methods in .NET 3.5 and LINQ, you have access to nearly all of the functionality from the original List<T> class in terms of querying, which is all you should do with a ReadOnlyCollection<T> anyways.

That being said, your initial question leads me to make some suggestions...

Returning List<T> is bad design, so it shouldn't be a point of comparison. List<T> should be used for implementation, but for the interface, IList<T> should be returned. The Framework Design Guidelines specifically state:

"DO NOT use ArrayList or List<T> in public APIs." (Page 251)

If you take that into consideration, there is absolutely no disadvantage to ReadOnlyCollection<T> when compared to List<T>. Both of these classes implement IEnumerable<T> and IList<T>, which are the interfaces that should be returned anyways.

Reed Copsey
Sadly the team is stuck in the time warp of 2.0.
Mark Levison
@Mark Levison: Even in 2.0, you should return IList<T>, not List<T>, so the comments still apply.
Reed Copsey
A: 

I think Jeff's answer kinda contains the answer you need; instead of ReadOnlyCollection<T>, return a subclass of it... one that you implement yourself to include the methods that you'd like to use without upgrading to VS2008/LINQ.

jerryjvl