While generics is interesting, the concept is mostly applied to classes. This is generally good, and in the .NET Framework 2.0, you can find a lot of classes that are built around this, like generic lists, dictionaries, Queues, ... A lot alike what can be found in the C++ STL.
But there is another interesting feature with generics : It can also be applied to methods in non-generic classes and interfaces.
I'm currently developping a new version of an internal Epitech Instant Messenger client which will run using .NET 2.0, and I'm trying to heavily use plugins. I'm going to skip the part about the plugins but, there is a point that is interesting. When a specific plugin wants to get an instance of an other plugin by using its interface type as an identifier, using .NET 1.1, I would have done something like this :
IContactList contactList = _core.GetPlugin(typeof(IContactList)) as IContactList;
The code is pretty easy to read. I'm trying here to get an instance of a IContactList plugin and use the as operator to avoid an exception if the plugin cannot be found.
But there is too much IContactList involved here. Ok, you'll tell me "Well, this is not a critical part of the application so, who cares ?". Well, I'm gonna tell you that I'm looking for the simplest user exposed code. So, using the .NET 2.0 generics features, I'm writing something like this :
IContactList contactList = _core.GetPlugin<IContactList>();
This is pretty much the same, but I've avoided writing IContactList twice and an as operator.
Overall, I haven't gained anything but less code to read. I don't gain anything in the type checking speed area, since I'm still doing an upcast in the GetPlugin method. By the way, here's what this method looks like :
public T GetPlugin< T>() where T : IPlugin
{
foreach (IPlugin plugin in _manager)
{
if (plugin.GetType().GetInterface(typeof(T).FullName) != null)
{
return (T)plugin;
}
}
return default(T);
}
I've also discovered a new use of the default keyword, which is used here to generate a default value for a type. If it's a value type, it's zero and if it's a reference type, it's null. I've also used the where clause, which forces the user of the GetPlugin method to specify a type that implements IPlugin prior to the call.
All this is interesting... I got used to the fact that I have to use general purpose collections and methods, but now C++ template reflexes are coming back ;) This is gonna be fun !