Introduction to Generics in C#
What are Generics?
Generics allow you to define a class, method, delegate, or interface with a placeholder for the type of data it stores or uses. This enables type-safe data structures without committing to actual data types until the class or method is instantiated or called.
Why Use Generics?
Generics provide several benefits:
- Type Safety: Generics ensure that you can only use the specified data type, reducing runtime errors.
- Performance: Generics can reduce the need for boxing/unboxing and type casting, which can improve performance.
- Code Reusability: Generic code can be reused with different data types, reducing code duplication.
Generic Classes
Here's an example of a generic class in C#:
public class GenericClass<T>
{
private T data;
public GenericClass(T value)
{
data = value;
}
public T GetData()
{
return data;
}
}
You can use this class with any data type:
GenericClass<int> intInstance = new GenericClass<int>(10);
Console.WriteLine(intInstance.GetData()); // Output: 10
GenericClass<string> stringInstance = new GenericClass<string>("Hello");
Console.WriteLine(stringInstance.GetData()); // Output: Hello
Generic Methods
Generic methods allow you to define a method with a type parameter. Here's an example:
public class GenericMethodClass
{
public void PrintData<T>(T data)
{
Console.WriteLine(data);
}
}
Using the generic method:
GenericMethodClass obj = new GenericMethodClass();
obj.PrintData<int>(123); // Output: 123
obj.PrintData<string>("Generics are powerful!"); // Output: Generics are powerful!
Generic Interfaces
Generic interfaces are similar to generic classes. Here's an example:
public interface IGenericInterface<T>
{
T GetData();
}
public class GenericClassWithInterface<T> : IGenericInterface<T>
{
private T data;
public GenericClassWithInterface(T value)
{
data = value;
}
public T GetData()
{
return data;
}
}
Implementing and using the generic interface:
IGenericInterface<int> intInstance = new GenericClassWithInterface<int>(10);
Console.WriteLine(intInstance.GetData()); // Output: 10
IGenericInterface<string> stringInstance = new GenericClassWithInterface<string>("Hello");
Console.WriteLine(stringInstance.GetData()); // Output: Hello
Constraints on Generics
Sometimes, you may want to restrict the types that can be used with generics. You can do this using constraints. Here are some examples of constraints:
// T must be a reference type
public class ReferenceTypeConstraint<T> where T : class
{
// Implementation
}
// T must be a value type
public class ValueTypeConstraint<T> where T : struct
{
// Implementation
}
// T must have a parameterless constructor
public class ConstructorConstraint<T> where T : new()
{
// Implementation
}
// T must inherit from a specific base class or implement a specific interface
public class BaseClassConstraint<T> where T : BaseClass
{
// Implementation
}
Conclusion
Generics are a powerful feature in C# that provide type safety, performance benefits, and code reusability. By understanding and utilizing generics, you can write more robust and maintainable code.