Generics

Added in .NET 2.0
Generics allow you to declare open types.
These open types are then converted into closed types at runtime.
Generics are most frequently used with Collections
These allow you to create type-safe components without actually committing to the actual data type.
A non-generic type is also known as as closed type.


These are most useful when used with container types such as lists, vectors, hash tables etc
Generics can treat the types that they contain specifically by their type rather than by using the object base type.
Allows you to create open-ended types that are converted to close types at runtime.


The type parameter T is used as a placeholder to represent any type


General Implementation - using object

Lets consider a very simple stack with a push and pop method
If you want to store any type of item in this stack you can declare it using the object data type.

public class MyStack 
{
   object[] _items;
   public void Push (object item)
   { .. }
   public object Pop()
   { .. }
}

There are two problems with this type of implementation:
1) Performance - when using value types you have to box and unbox the value types and when using reference types you have to explicitly cast them.
2) Type safety - this is lost because the compiler will let you cast anything to and from an object type.


Type Specific Implementations

You can overcome these two problems by providing type-specific implementations for all the different data types.
For example a stack of integers could be defined by:

public class IntegerStack 
{
   int[] _items;
   public void Push (int item)
   { .. }
   public int Pop()
   { .. }
}

You could also implement other type specific versions but this introduces a different problem.
3) Duplicating code - writing type-specific components leads to a duplication of code and is much more error prone.


Generic Implementation

All of these problems are resolved by using Generics
Generics allow you to define type-safe classes without compromising performance or duplicating code.
You can write the code once and specify the data type when its used.


The more advanced collections can be found in the System.Collections.Specialized namespace


Everytime you retrieve an object from a general collection you must cast it to the appropriate type.
You can create your own generic collections as well as use any of the built-it generic classes.


public class MyStack<T> 
{
   T[ ] _items;
   public void Push(T item)
   { }
   public T Pop()
   { }
}

MyStack<int> mystack = new MyStack<int>();
mystack.Push(5);
mystack.Push(10);
int number = mystack.Pop();

When using a generic stack you must specify the data type you want to use both when you declare the variable and when you instantiate it.
T is the type parameter (or generic type parameter)
MyStack<T> is the generic type




Derivation Constraints - where

You can use the where keyword to define a constraint on the generic type parameter
This tells the compiler that the generic type parameter implements a particular interface


Constructor Constraint - new()

This tells the compiler that the generic type parameter must support a public default constructor



default(T)

This can be used to return the default value of the generic type parameter.




Generic Type Parameters




Generic.KeyValuePair
This stores pairs of values that can be set or retrieved
The key and value properties must be assigned on initialisation
A Dictionary class is a data structure that represents a collection of key-value pairs.


Dictionary<string, int> MyDictionary = new Dictionary<string, int>(); 
foreach (KeyValuePair<string, int> item in MyDictionary)
{
// ...
}



© 2024 Better Solutions Limited. All Rights Reserved. © 2024 Better Solutions Limited TopNext