It’s so important to properly protect your internals of an object, especially collections. I’m going rant for a bit about why the following piece of code drives me a little nutty!
Why is this so wrong… because it does not keep the ruffians out.
When you expose a collection as a property on a component you expose the innards of the component. Clients of the component can inject state that was not meant to be there. Does that suck? YUP!
So how do we deal with this? You separate the behavior of add new exclusive members from checking the exclusive members roster. When you’re viewing the roster, you’re doing so in a read only manner. Clients who are checking out the roster should not have access to sneaking in new exclusive members.
Enter the IEnumerable interface. All collections types implement the IEnumerable interface, it’s contract allows consumers to walk a collection but not sneak members in. Or does it? Let’s take a look at a revised contract for the Country Club.
Looks alright for now. Let’s peak at an implementation or the contract…
IEnumerable doesn’t have an add method so I guess clients shouldn’t be able to sneak in now right? Let’s see what those ruffians come up with…
They did it again, those ruffians are a persistent bunch. They guessed that the roster of members were composed in a collection of type List, and they were right! They snuck in again!
We can keep those ruffians out by building an instance of a type that implements the IEnumerable interface but doesn’t hand out our internal collection. The following code does just that:
The above code compiles down to a full blown Enumerable type. Kind of like the code below, you can go check out the IL produced from the above and see what it translates too…
One additional thing that the yield return keyword offers is deferred execution. This concept is getting a lot more attention now in C# 3.0, but it was already available in C#2.0. More on that later…
If the purpose of exposing the IList interface on a type instead of the IEnumerable interface is to leverage the sorting methods then I suggest you factor out a separate interface specifically for traversing a collection and being able to query it. I spoke of a RichEnumerable interface that allowed you to do so, but the new language features in C# 3.0 and specifically the IQueryable interface looks like it might make this much easier to traverse a collection and sort and query it as needed.
New interfaces to check out:
- IGrouping<TKey, TElement>
- ILookup<TKey, TElement>
My personal preference is to drop the properties… In my mind when I see a call to a method, I think this is invoking and action or triggering some sort of behavior, and in this example it is. We’re building up a type that we serve back to a client to allow them to traverse our internals without completely handing it out. Anyway’s, I wont fight the battle with properties today… but maybe I can save that for a later rant.