Now we have reached Part 3 in this series of articles. So far I have discussed the DataReader, the untyped DataSet, and the typed DataSet. In this article, I focus on wrapping a container datatype and directly using a generic container datatype. In the wrapper discussion, I will wrap a DataSet in my examples; to illustrate the direct use of a generic container datatype, I will use a Hashtable.
Reuse by Inheritance or Containment
In Part 2 of this series, I discussed untyped and typed DataSets. The typed DataSet "is-an" untyped DataSet. The typed DataSet is derived from (or inherits from) the untyped DataSet. As a result, the typed DataSet gets all its functionality from the untyped DataSet and only has to extend the extra functionality. Another good thing is that because of the inheritance relationship, you can treat and work with a typed DataSet as if it were an untyped DataSet. This can be good, but encapsulation will be too weak. If you remember the old days before .NET, Microsoft always told us that reuse by containment was to be preferred over reuse by inheritance. COM didn't support inheritance, but that wasn't the only reason for that recommendation.
I'm not trying to say that inheritance is bad. But containment is preferred in some situations. To make a long story short, I'm not fond of the fact that typed DataSets inherit from untyped DataSets. By using containment instead, it's possible to increase encapsulation a lot by providing just a minimal interfaceblack box reuse instead of white box reuse.
According to Robert C. Martin's great book "Agile Software Development: Principles, Patterns, and Practices" (Prentice Hall, 2002), "is-a" is too broad for explaining subtypes in an inheritance relationship. "Substitutable" is better. Regardless, my main objective regarding typed DataSets still stands.