Generic Classes in C# 2.0

Code once. Use many. That's what generics are about. Called templates in C++, C# generics support separating code by algorithm and data structure. For example, the generic list means that you'll never again have to write a strongly typed collection. Paul Kimmel shows just how easy it is to define and use generics, long considered one of the most advanced and difficult idioms. This article is adapted from Paul Kimmel's book C# Express (Addison-Wesley).

Like this article? We recommend

Introduction

Generics are considered an advanced and powerful idiom in any
language. When I first encountered templates in C++, they seemed a little
confusing. Then I read Bjarne Stroustrop's
The Design and Evolution of C++,
and templates seemed as easy to use as the C macros and simple
string-replacement templates they supplanted. Templates and generics are the
same thing—though their implementations are slightly different.

Generics in C# support defining algorithms and deferring the data type until
the point of use. In early versions of C#, we arguably could live without
generics because every type was derived from a common base type:
object. This meant that programmers could define a Stack class
based on the object type and put anything in the Stack
(because everything's earliest ancestry is an object). However, a
Stack of objects meant that Customerobjects, Integerobjects, and Fooobjects could all be placed in the same Stack instance. The
result was that developers subclassed data types to tighten up the type of data
with which they interacted. For example, when writing custom business objects,
it was a recommended practice to define strongly typed collections derived from
System.Collections.CollectionBase. The reason is simple: Defining
everything based on objects is considered weak typing.

The industry's best minds have believed for a couple of decades that
strong typing is preferable to weak typing, so it seems natural that .NET
eventually had to support strong typing. Strongly typed algorithms naturally
suggest parameterized types, which is where we are with generics.

For more than a decade, we've used the letter T as the name for
parameterized types. Thus, anywhere the data type is meant to be provided by the
generic class consumer, you'll find a T. The key to using
generics is simply to provide the T. The key to defining
generics is to implement a method or class and replace specific data types with
T.

Generics in C# support some additional refinements. For example, a method or
class can have more than one parameterized type, and generics in C# support
WHERE constraints that refine the type of the parameterized types. For
example, if a generic type must implement IDisposable, C# generics
support expressing this limitation. We'll look at constraints later in this
article.