- They provide a facility for creating data structures that are specialized to handle specific types when declaring a variable.
- C# generics are a type-safe implementation of templates.
Generic Interfaces and Structs
- Implementing a generic interface without identifying the type parameter forces the class to be a generic class.
- By using generic interfaces, you can avoid cast operations because a stronger compile-time binding can be achieved with parameterized interfaces.
Implementing the Same Interface Multiple Times on a Single Class
- You can implement the same interface many times using different type parameters:
public interface IContainer<T>
{
ICollection<T> Items { get; set; }
}
public class Person : IContainer<string>, IContainer<int>, IContainer<bool>
{
ICollection<string> IContainer<string>.Items { get; set; }
ICollection<int> IContainer<int>.Items { get; set; }
ICollection<bool> IContainer<bool>.Items { get; set; }
}
Defining a Constructor/Finalizer
public interface IPair<T>
{
T First { get; set; }
T Second { get; set; }
}
public struct Pair<T> : IPair<T>
{
public T First { get; set; }
public T Second { get; set; }
public Pair(T first, T second)
{
First = first;
Second = second;
}
}
Specifying a Default Value for Value Types
- In the example above, consider a constructor for Pair<T> that initializes only half of the pair at instantiation time.
- This causes a compile error because the field Second goes uninitialized at the end of the constructor.
- Providing initialization for Second presents a problem since you don’t know the data type of T.
- If it is a reference type, then null would work, but this would not suffice if T were a value type (unless it was nullable).
public struct Pair<T>: IPair<T>
{
/*
// ERROR: Field 'Pair<T>.Second' must be fully assigned before control leaves the constructor
public Pair(T first)
{
_First = first;
}
*/
}
- To deal with this scenario, you can set the default value of any data type using the
default
operator.
public struct Pair<T> : IPair<T>
{
public Pair(T first)
{
First = first;
Second = default(T);
}
}
Constraints
- A constraint is an optional list for each generic class type parameter and declares the type parameter characteristics that the generic requires.
Interface Constraints
public class BinaryTree<T>
where T : IComparable<T> { /* ... */ }