This blog is going to have surfing, snowboarding, tech stuff and maybe some 'meaning of life' stuff if I'm feeling particularly stoked.

Sunday, November 28, 2004

Generics

The other day someone asked me about the new CLR feature of Generics and I felt that my answer wasn’t exactly crystal clear. I believe this was because I was so accustomed to using templates in C++ whereas the enquirer had no background in C++ at all.

Perhaps if I blog on the subject I will be better prepared the next time I am asked.

Most of the information I have seen so far on Generics talks about writing generic types and generic methods when in fact the vast majority of people will use generic classes rather than actually author them. For example, with C++ templates, I used them all the time in STL and more abstractly in ATL yet I don’t think I have ever written a template class in production code.

Therefore I am going to focus only on the new generic BCL classes which ship with 2.0 and use these to illustrate the features & benefits of generics. I am deliberately not touching on the subject of performance since this is a post in itself (which I will hopefully do) and requires a much deeper understanding of generics and the CLR.

At a most basic level, generic classes will provide developers with the option of using strongly-typed collection classes without having to rewrite the standard collection functionality (Add(), Remove(), GetValue(), etc) each time.

On my current project we tend to use the existing BCL collection classes like Hashtable, ArrayList, etc and therefore we live with the runtime type checking that is necessary because these classes treat everything as the base type Object. A benefit of these "any type" collections is that there was no need to reimplement the common collection methods (Add, Remove, etc) for specialised types (e.g. our Account class). One of the drawbacks of this approach was that less experienced developers were often unsure about which type should go in which collection and this inevitably resulted in runtime Invalid Cast exceptions.

private HashTable custHT = new Hashtable(30);
...


custHT.Add(idxCustName, "CustomerName"); // would compile
custHT.Add(idxCustName, 32); // would also compile


A sub-system which had a different design team (still in-house) decided to go with strongly typed collection classes derived from BCL collection base classes (i.e. System.Collections.CollectionBase) . The benefit of this was that types (e.g. the Role class) were all known at compile time and any mismatch would not be tolerated by the compiler. A drawback was the amount of repeated code along with a fair number of essentially “incomplete” collections where methods were not implemented if they were not immediately required.

private IRoleCollection roleCollection = new RoleCollection();
...


// Use IRoleCollection method AddRole(Int32 roleId, IRole roleToAdd)

roleCollection.AddRole(1, aRole); // would compile
roleCollection.AddRole(1, 32); // would not compile

Generics will bridge the gap between these two approaches by providing classes such as Dictionary which can be strongly typed at compile time yet still provide all the functionality of the "any type" class Hashtable.

using System.Collections.Generic;
...


private Dictionary genDic = new Dictionary(30);
...


genDic.Add(idxCustName, “CustomerName”); // would compile
genDic.Add(idxCustName, 32); // would not compile




To summarise, CLR generics, at their most basic level, provide type safety and encourage code reuse.

In later posts I will attempt to cover design & development of generic types and methods, dig into the internals of generics and look at how generics could improve performance.

b.