Generics in C# are a feature that allows the design of classes, interfaces, and methods where the specification of one or more data types is deferred until the code is declared and instantiated. This provides type safety and performance without requiring the manual duplication of identical logic across data types.
What Are Generics?
Generics allow defining classes, methods, and interfaces with a placeholder type instead of a fixed type. Think of generics as a container that works with any type, while still giving type safety.
Imagine a ShippingBox class used to ship various items.
Without Generics: Defining a separate box class for every item type would require IntBox, StringBox, LaptopBox, and so on. This approach creates redundant code.
With Generics: Generics enable the creation of a single versatile class, ShippingBox<T>, where T serves as a placeholder. When used, the exact content type is specified, such as ShippingBox<Laptop> or ShippingBox<Book>. The compiler enforces that only an item of the specified type can be placed inside, like a book in ShippingBox<Book>, ensuring type safety and eliminating redundancy.
This design improves code reusability and enforces compile-time type checking, preventing errors and making the codebase cleaner and easier to maintain.
Core Concepts of Generics
1. Type Parameters
Type parameters are the placeholders for types. They are typically represented by a single capital letter, most commonly T (for Type). They are declared inside angle brackets (<T>) immediately following the class, interface, or method name.
2. Generic Classes and Interfaces
These are classes or interfaces defined with one or more type parameters.
// The type parameter T is a placeholder for any type
public class Repository<T>
{
private List<T> _items = new List<T>();
public void Add(T item)
{
_items.Add(item);
}
// ... other methods that work with T
}3. Generic Methods
A method can be generic even if it belongs to a non-generic class, or it can be a generic method inside a generic class.
public static void Swap<T>(ref T firstValue, ref T secondValue)
{
T temp = firstValue;
firstValue = secondValue;
secondValue = temp;
}
// Usage example:
string studentName1 = "Alice";
string studentName2 = "Bob";
Swap(ref studentName1, ref studentName2); // Swaps student names
int studentId1 = 101;
int studentId2 = 202;
Swap(ref studentId1, ref studentId2); // Swaps student IDs
4. Type Constraints
Type constraints restrict the types that can be substituted for the type parameter T. They enforce rules that allow the generic code to safely call methods or use properties of the placeholder type.

Join the conversation! Your thoughts help the community grow.