Limitations of generic base classes
This post was originally published here.
I thought I had created something fairly useful with a generic Value Object in a previous post. Generic base classes are nice, and there are several recommended base classes for creating collections classes. Whenever I try to make an interesting API with a generic base class, limitations and faulty assumptions always reduce the usefulness of that base class. Let’s first start with a couple of classes that we’d like to include in a generic API:
public class Address
{
private readonly string _address1;
private readonly string _city;
public Address(string address1, string city)
{
_address1 = address1;
_city = city;
}
public string Address1
{
get { return _address1; }
}
public string City
{
get { return _city; }
}
}
public class ExpandedAddress : Address
{
private readonly string _address2;
public ExpandedAddress(string address1, string address2, string city)
: base(address1, city)
{
_address2 = address2;
}
public string Address2
{
get { return _address2; }
}
}
Fairly basic classes, just two types of addresses, with one a subtype of the other. So what kinds of issues do I usually run in to with generic base classes? Let’s look at a few different types of generic base classes to see.
Concrete generic implementations
A concrete generic implementation is a concrete class that inherits a generic base class:
public class AddressCollection : Collection<Address>
{
public AddressCollection() {}
public AddressCollection(IList<Address> list) : base(list) {}
}
Following the Framework Design Guidelines, I created a concrete collections class by inheriting from [System.Collections.ObjectModel.Collection
- Create an ExpandedAddressCollection class inheriting from AddressCollection
- Create an ExpandedAddressCollection class inheriting from Collection
- Use the existing AddressCollection class and put ExpandedAddress instances in it.</ul> All of these seem reasonable, right? Let’s take a closer look.
Inherit from AddressCollection
Here’s what the ExpandedAddressCollection class would look like:
public class ExpandedAddressCollection : AddressCollection
{
public ExpandedAddressCollection() {}
public ExpandedAddressCollection(IList<Address> list) : base(list) {}
}
- Create an ExpandedAddressCollection class inheriting from Collection
</pre> </div>
That’s not very interesting, it didn’t add any information to the original AddressCollection. What’s more, this ExpandedAddressCollection ultimately inherits Collection<Address>, _not_ Collection<ExpandedAddress>. Everything I try to put in or get out will be an Address, not an ExpandedAddress. For example, this code wouldn’t compile:
<div class="CodeFormatContainer">
<pre>List<ExpandedAddress> addresses = <span class="kwrd">new</span> List<ExpandedAddress>();<br /> addresses.Add(<span class="kwrd">new</span> ExpandedAddress(<span class="str">"Address1"</span>, <span class="str">"Austin"</span>, <span class="str">"TX"</span>));<br /> <br /> ExpandedAddressCollection addressList = <span class="kwrd">new</span> ExpandedAddressCollection(addresses);<br />
</pre> </div>
Because of limitations in generic variance, namely that C# [does not support](http://msdn2.microsoft.com/en-us/library/ms228359(vs.80).aspx) generic [covariance or contravariance](http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx). Even though ExpandedAddress is a subtype of Address, and ExpandedAddress[] is a subtype of Address[], IList<ExpandedAddress> **is not** a subtype of IList<Address>.
#### Inherit from Collection<ExpandedAddress>
In this example, I’ll just implement the ExpandedAddressCollection in the same manner as AddressCollection:
<div class="CodeFormatContainer">
<pre><span class="kwrd">public</span> <span class="kwrd">class</span> ExpandedAddressCollection : Collection<ExpandedAddress><br /> {<br /> <span class="kwrd">public</span> ExpandedAddressCollection() {}<br /> <br /> <span class="kwrd">public</span> ExpandedAddressCollection(IList<ExpandedAddress> list) : <span class="kwrd">base</span>(list) { }<br /> }<br />
</pre> </div>
Now I my collection is strongly types towards ExpandedAddresses, so the example I showed previously would now compile. It seems like I’m on the right track, but I run into even more issues:
* ExpandedAddressCollection is not a subtype of AddressCollection
* Collection hierarchy does not match hierarchy of Addresses (one is a tree, the other is flat)
* I can’t pass an ExpandedAddressCollection into a method expecting an AddressCollection
* Since there is no relationship between the two collection types, I can’t use many patterns where a relationship is necessary</ul>
So even though my collection is strongly typed, it becomes severely limited in more interesting scenarios.
#### Use existing AddressCollection class
In this instance, I won’t even create an ExpandedAddressCollection class. Any time I need a collection of ExpandedAddresses, I’ll use the AddressCollection class, and cast as necessary. I won’t be able to pass an IList<ExpandedAddress> to the constructor because of the variance issue, however. If I need to include some custom logic in the collection class, I’ll run into the same problems highlighted earlier if I’m forced to create a new subtype of AddressCollection.
So we’ve seen the limitations of concrete generic implementations, what other options do I have?
### Constrained generic base classes
I’d like a way to propagate the concrete type parameter back up to the original Collection<T>. What if I make the AddressCollection generic as well? Here’s what that would look like:
<div class="CodeFormatContainer">
<pre><span class="kwrd">public</span> <span class="kwrd">class</span> AddressCollection<T> : Collection<T><br /> <span class="kwrd">where</span> T : Address<br /> {<br /> <span class="kwrd">public</span> AddressCollection() {}<br /> <br /> <span class="kwrd">public</span> AddressCollection(IList<T> list) : <span class="kwrd">base</span>(list) {}<br /> }<br /> <br /> <span class="kwrd">public</span> <span class="kwrd">class</span> ExpandedAddressCollection : AddressCollection<ExpandedAddress><br /> {<br /> <span class="kwrd">public</span> ExpandedAddressCollection() {}<br /> <br /> <span class="kwrd">public</span> ExpandedAddressCollection(IList<ExpandedAddress> list) : <span class="kwrd">base</span>(list) { }<br /> }<br />
</pre> </div>
So now I have a constrained base class for an AddressCollection, and an implementation for an ExpandedAddressCollection. What do I gain from this implementation?
* ExpandedAddressCollection is completely optional, I could just define all usage through an AddressCollection<ExpandedAddress>
* Any AddressCollection concrete type will be correctly strongly typed for an Address type</ul>
Again, with some more interesting usage, I start to run into some problems:
* I can never reference only AddressCollection, as I always have to give it a type parameter.
* Once I give it a type parameter, I run into the same variance issues as before, namely AddressCollection<ExpandedAddress> is not a subtype of AddressCollection<Address>
* Since I can never define any method in terms of solely an AddressCollection, I either need to make the containing class generic or the method generic.</ul>
For example, I can write the following code:
<div class="CodeFormatContainer">
<pre><span class="kwrd">public</span> <span class="kwrd">void</span> TestGenerics()<br /> {<br /> AddressCollection<Address> addresses = <span class="kwrd">new</span> AddressCollection<Address>();<br /> addresses.Add(<span class="kwrd">new</span> Address(<span class="str">"132 Anywhere"</span>, <span class="str">"Austin"</span>));<br /> <br /> <span class="kwrd">int</span> count = NumberOfAustinAddresses(addresses);<br /> <br /> AddressCollection<ExpandedAddress> expAddresses = <span class="kwrd">new</span> AddressCollection<ExpandedAddress>();<br /> expAddresses.Add(<span class="kwrd">new</span> ExpandedAddress(<span class="str">"132 Anywhere"</span>, <span class="str">"Apt 123"</span>, <span class="str">"Austin"</span>));<br /> <br /> count = NumberOfAustinAddresses(addresses);<br /> }<br /> <br /> <span class="kwrd">private</span> <span class="kwrd">int</span> NumberOfAustinAddresses<T>(AddressCollection<T> addresses)<br /> <span class="kwrd">where</span> T : Address<br /> {<br /> <span class="kwrd">int</span> count = 0;<br /> <span class="kwrd">foreach</span> (T address <span class="kwrd">in</span> addresses)<br /> {<br /> <span class="kwrd">if</span> (address.City == <span class="str">"Austin"</span>)<br /> count++;<br /> }<br /> <span class="kwrd">return</span> count;<br /> }<br />
</pre> </div>
This isn’t too bad for the implementation nor the client code. I don’t even need to specify a generic parameter in the method calls. If I can live with generic methods, this pattern might work for most situations.
The only other problem I’ll have is that I might need to create subtypes of AddressCollection, like I did above with ExpandedAddressCollection. In this case, I’d can continue to make each subtype generic and constrained to the derived type:
<div class="CodeFormatContainer">
<pre><span class="kwrd">public</span> <span class="kwrd">class</span> ExpandedAddressCollection<T> : AddressCollection<T><br /> <span class="kwrd">where</span> T : ExpandedAddress<br /> {<br /> <span class="kwrd">public</span> ExpandedAddressCollection() {}<br /> <br /> <span class="kwrd">public</span> ExpandedAddressCollection(IList<T> list) : <span class="kwrd">base</span>(list) { }<br /> }<br />
</pre> </div>
Again, if I can live with generic methods, I would be happy with this implementation, as I now keep the same hierarchy as my Addresses. It is a little strange declaring ExpandedAddressCollection with a type parameter (ExpandedAddressCollection<ExpandedAddress>), but I’ll live.
There’s one more type of generic base class I’d like to explore.
### Self-constrained generic base classes
Sometimes, I need to implement a certain generic interface, such as IEquatable<T>. I could simply pass in the concrete type into the generic parameter like this:
<div class="CodeFormatContainer">
<pre><span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">class</span> ValueObject : IEquatable<ValueObject><br />
</pre> </div>
But if I’m trying to create an abstract or a base class for subtypes to use, I’ll run into problems where derived types won’t implement IEquatable<DerivedType>. Instead, I can make this abstract class generic and self-constraining:
<div class="CodeFormatContainer">
<pre><span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">class</span> ValueObject<T> : IEquatable<T><br /> <span class="kwrd">where</span> T : ValueObject<T><br />
</pre> </div>
Now, derived types will implement IEquatable<DerivedType>, as I showed in my [post on value types](https://lostechies.com/blogs/jimmy_bogard/archive/2007/06/25/generic-value-object-equality.aspx). Unfortunately, subtypes will only implement the correct IEquatable<T> for the first derived class:
<div class="CodeFormatContainer">
<pre><span class="kwrd">public</span> <span class="kwrd">class</span> Address : ValueObject<Address><br /> <span class="kwrd">public</span> <span class="kwrd">class</span> ExpandedAddress : Address<br />
</pre> </div>
In this case, ExpandedAddress is not a subtype of ValueObject<ExpandedAddress>, and therefore only implements IEquatable<Address>. I can’t use the same tricks with the constrained generic base class, as I would need to declare Address as generic, and therefore never instantiable by itself. The self-constrained generic base or abstract class is unfortunately only useful in hierarchies one level deep.
### Conclusion
So generics aren’t the silver spoon I thought it would be, but there are some [interesting proposals to allow variance](http://research.microsoft.com/~akenn/generics/ECOOP06.pdf) for generic types out there. I might not be able to cover all of the scenarios I’d like for a generic base class, but by identifying several options and their consequences, I can make a better decision on solving the problem.