Generics in C#
are a powerful feature used to create reusable, type-safe, and high-performance code by using placeholders (typically T) for data types which are specified at compile time. They eliminate the need for repetitive code for different types and avoid the overhead of boxing and unboxing associated with non-generic collections like ArrayList.
Generic Classes
You can define a class with one or more type parameters (T, TKey, TValue, etc.) to create a single class definition that works with various data types. The most common examples in the .NET framework are collection classes such as List and Dictionary<TKey, TValue>.
Generic Methods
A single method can be declared as generic to work with different data types. The type parameter is specified when the method is called. This is useful for writing utility functions like a generic Swap<T> method that can exchange values of any type, or methods that handle data serialization/deserialization.</T>
Generic Interfaces
You can define interfaces with type parameters, allowing classes that implement the interface to specify the data type they will handle.
Generic Delegates and Events
Generics can also be used with delegates and events, providing type safety for event handlers and callbacks that need to operate on specific data types.
Generic Constraints
The where keyword is used to apply constraints to type parameters, restricting which types can be used as arguments. This allows you to call methods or access properties of the constrained type. Constraints can specify: where T : class (must be a reference type), where T : struct (must be a non-nullable value type), where T : new() (must have a parameterless constructor), where T : BaseClass (must inherit from a specific base class), where T : Interface (must implement a specific interface).
Covariance and Contravariance
These advanced features allow for implicit reference conversions in generic interfaces and delegates. Covariance (out T) allows a generic type to use a more derived type, while contravariance (in T) allows it to use a less derived type.
In summary
generics allow developers to write flexible code that adheres to the “Don’t Repeat Yourself” (DRY) principle, improving code quality and maintainability across various components of a C# application.