So I was reading this long and enlightening article, written by someone waaay smarter than myself, about variance for generics and I encountered a cool new feature in C# 2.0. Simply put, when you define a Generic method, you can apply restrictions (constraints) to the kinds of types that client code can use when it calls your method. For example, you run into a problem if you want to copy a List<int> into a List<object>. This seems like a reasonable thing to do because an int is an object, but the language simply doesn't support this (yet).
List<int> ints = new List<int>();
ints.Add(1);
ints.Add(10);
ints.Add(42);
List<object> objects = new List<object>();
// doesn’t compile because ‘ints’ is not a IEnumerable<object>
objects.AddRange(ints);
To work around this problem you might create the following function:
public static void Add<S, D>(List<S> source, List<D> destination) where S : D
{
foreach(S sourceElement in source)
destination.Add(sourceElement);
}
Take special note of the part that says “where S : D”. This will constrain the type of S to be, or derive from, the type of D. In fact, if you leave the constraint off, you get a compile time error because “sourceElement” is not of the correct type. Slick, eh? There are five types of constraints you can use and they are all listed [here].