Generics in C# Programming
Generics in C# allow you to define type-safe data structures and methods. They provide better performance and reusability by enabling the creation of classes, methods, and interfaces that work with any data type while maintaining type safety at compile time.
1. Generic Classes and Methods
Generic classes and methods allow you to define a class or method with a placeholder for the type of data it stores or operates on.
Step-by-Step Example: Generic Classes
using System; // Generic class class GenericStorage{ private T item; public void StoreItem(T value) { item = value; } public T RetrieveItem() { return item; } } class Program { static void Main() { // Create instances of GenericStorage for different types GenericStorage intStorage = new GenericStorage (); intStorage.StoreItem(42); Console.WriteLine("Stored integer: " + intStorage.RetrieveItem()); GenericStorage stringStorage = new GenericStorage (); stringStorage.StoreItem("Hello Generics"); Console.WriteLine("Stored string: " + stringStorage.RetrieveItem()); } }
Output:
Stored integer: 42
Stored string: Hello Generics
Step-by-Step Example: Generic Methods
using System; class Program { // Generic method static void Display(T value) { Console.WriteLine("Value: " + value); } static void Main() { Display(100); // Using an int Display("Generics"); // Using a string Display(3.14); // Using a double } }
Output:
Value: 100
Value: Generics
Value: 3.14
2. Constraints in Generics
Constraints allow you to specify the types that can be used with a generic class or method. This ensures type safety and allows access to specific features of the constrained type.
Types of Constraints
- where T : struct - T must be a value type.
- where T : class - T must be a reference type.
- where T : new() - T must have a parameterless constructor.
- where T : BaseClass - T must inherit from BaseClass.
- where T : interface - T must implement the specified interface.
Step-by-Step Example: Constraints in Generics
using System; // Generic class with constraints class GenericCalculatorwhere T : struct { public T Add(T a, T b) { dynamic x = a; dynamic y = b; return x + y; } } class Program { static void Main() { // Create an instance of GenericCalculator for integers GenericCalculator intCalculator = new GenericCalculator (); Console.WriteLine("Sum of integers: " + intCalculator.Add(10, 20)); // Create an instance of GenericCalculator for doubles GenericCalculator doubleCalculator = new GenericCalculator (); Console.WriteLine("Sum of doubles: " + doubleCalculator.Add(5.5, 3.3)); } }
Output:
Sum of integers: 30
Sum of doubles: 8.8
Example: Using Multiple Constraints
using System; // Generic class with multiple constraints class GenericRepositorywhere T : class, new() { public T CreateInstance() { return new T(); } } class Program { static void Main() { GenericRepository repository = new GenericRepository (); MyClass instance = repository.CreateInstance(); Console.WriteLine("Instance created: " + instance.Name); } } class MyClass { public string Name { get; set; } = "Default Name"; }
Output:
Instance created: Default Name
Conclusion
Generics in C# offer flexibility and type safety for creating reusable code. Generic classes and methods are powerful tools, and constraints ensure that the types used meet specific requirements. Understanding and using generics effectively can greatly enhance the efficiency of your C# programs.