Introduction
Generics in C# are a powerful feature that allows developers to write flexible, reusable, and type-safe code. Instead of creating separate classes or methods for different data types, generics enable you to define a single implementation that works with multiple types while maintaining compile-time type safety.
This article explains how to use generics in C#, why they are important, and how they improve code reusability and performance with real-world examples.
What Are Generics in C#?
Generics allow you to define classes, methods, interfaces, and delegates with a placeholder type (usually represented by T). This type is specified when the class or method is used.
Basic Example
class GenericClass<T>
{
public T Data;
public void ShowData(T value)
{
Console.WriteLine(value);
}
}
class Program
{
static void Main()
{
GenericClass<int> intObj = new GenericClass<int>();
intObj.ShowData(10);
GenericClass<string> strObj = new GenericClass<string>();
strObj.ShowData("Hello Generics");
}
}
In this example, the same class works with both int and string types without duplicating code.
Why Use Generics in C#?
Generics solve common problems related to code duplication and runtime errors.
Key Benefits
Type Safety: Errors are caught at compile time instead of runtime
Code Reusability: One implementation works for multiple data types
Performance: No boxing and unboxing for value types
Maintainability: Cleaner and more structured code
Generic Methods in C#
You can also create methods that work with different data types.
Example
class Utility
{
public static void Print<T>(T value)
{
Console.WriteLine(value);
}
}
class Program
{
static void Main()
{
Utility.Print<int>(100);
Utility.Print<string>("Reusable Method");
}
}
This method can accept any type without needing multiple overloads.
Generic Collections in C#
C# provides built-in generic collections that are widely used in real-world applications.
Example Using List
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> names = new List<string>();
names.Add("Rahul");
names.Add("Amit");
foreach (var name in names)
{
Console.WriteLine(name);
}
}
}
Generic collections like List, Dictionary<TKey, TValue>, and Queue provide type safety and better performance.
Generic Constraints in C#
Sometimes you want to restrict the type that can be used with generics. This is done using constraints.
Example
class Calculator<T> where T : struct
{
public T Value;
}
Here, T must be a value type (like int, double, etc.).
Common Constraints
where T : class → reference types only
where T : struct → value types only
where T : new() → must have a parameterless constructor
where T : BaseClass → must inherit from a specific class
Real-World Example of Generics
Consider a repository pattern in a real-world application.
class Repository<T>
{
private List<T> items = new List<T>();
public void Add(T item)
{
items.Add(item);
}
public List<T> GetAll()
{
return items;
}
}
class Program
{
static void Main()
{
Repository<string> repo = new Repository<string>();
repo.Add("Data 1");
repo.Add("Data 2");
foreach (var item in repo.GetAll())
{
Console.WriteLine(item);
}
}
}
This allows the same repository to work with any entity type without rewriting code.
Difference Between Generics and Non-Generics
| Feature | Generics | Non-Generics |
|---|
| Type Safety | Compile-time | Runtime |
| Performance | Better (no boxing) | Slower (boxing/unboxing) |
| Reusability | High | Low |
| Code Clarity | Clean and structured | Less clear |
When to Use Generics
Use generics when:
You want reusable components
You want to avoid duplicate code
You need type safety
You are working with collections or data structures
Key Takeaways
Generics enable reusable and type-safe programming in C#
They reduce runtime errors and improve performance
They are widely used in collections, repositories, and frameworks
Summary
Generics in C# provide a clean and efficient way to write reusable and type-safe code by allowing developers to define flexible components that work with multiple data types. They improve performance by avoiding unnecessary type conversions, enhance code readability, and reduce duplication. By using generics in classes, methods, and collections, developers can build scalable and maintainable applications that follow modern software development best practices.