Generic collections: Decisions around type support for your generic parameters
Originally in my heap class,
null was a special value. The type of the heap was always
object and so this made sense. Either the contained item was a reference type and null was a natural value to store for no item, or it was a boxed value type (which performed poorly but worked fine). When moving to a generic implementation, you've got to think about how dependent you are on these kind of special values. If you don't have a lot of reliance on them then the approach I took may work well for you. I simply substituted
When the top object was extracted from the heap, I was simply using
null to break the reference from the heap to the object it previously contained and so was holding alive. For a reference type, the default value is null anyway, so this still works. For value types, it doesn't really matter what the value used is as we're not holding anything up as far as garbage collection is concerned.
If you're using
null as a special value in your APIs then you're in for more work. For instance, you might previously have returned null from a "Find" method to indicate that no value was found. If you allow your collection to take any generic parameter, then null is no longer a valid return value for that method if the generic type is a value type, so you're stuck. There are a couple of routes you could go down here:
If you don't need to be able to support value types, you could constrain your generic parameter to be a reference type by using the
where T : class technique. EricGu has an article on the topic here.
You can alter the "Find" method to separate the "found" boolean value from the "what was found" value of type "T". This is the approach taken by the Dictionary class in the BCL which is largely analogous to the Hashtable class in previous versions. You can take a look at its TryGetValue method to see the implementation yourself. Although normally, I'd see separation of concerns as a great principle for design, I think its inescapable that using this new API is less readable than the old method which had the luxury of being able to return
null - you always pay some price for progress.