C# - Generics
Generics in C# allow you to define classes, interfaces, and methods with a placeholder for the data type. This enables you to create type-safe data structures and algorithms while avoiding code duplication. Generics provide flexibility and reusability by letting you define a class or method with a type parameter that is specified when the class or method is instantiated or called.
1. Generic Classes
A generic class allows you to define a class with a type parameter.
Syntax:
csharppublic class GenericClass<T>
{
private T data;
public GenericClass(T value)
{
data = value;
}
public T GetValue()
{
return data;
}
}
Example:
csharpGenericClass<int> intInstance = new GenericClass<int>(42);
Console.WriteLine(intInstance.GetValue()); // 42
GenericClass<string> stringInstance = new GenericClass<string>("Hello");
Console.WriteLine(stringInstance.GetValue()); // Hello
2. Generic Methods
A generic method allows you to define a method with a type parameter.
Syntax:
csharppublic T GenericMethod<T>(T value)
{
return value;
}
Example:
csharppublic T Echo<T>(T input)
{
return input;
}
int number = Echo(123); // 123
string text = Echo("Hello"); // "Hello"
3. Generic Interfaces
A generic interface defines a contract with type parameters.
Syntax:
csharppublic interface IGenericInterface<T>
{
T GetValue();
void SetValue(T value);
}
Example:
csharppublic class GenericImplementation : IGenericInterface<int>
{
private int data;
public int GetValue()
{
return data;
}
public void SetValue(int value)
{
data = value;
}
}
4. Constraints on Generics
Constraints allow you to restrict the types that can be used as arguments for generic type parameters.
Common Constraints:
where T : struct
: Specifies that the type parameter must be a value type.where T : class
: Specifies that the type parameter must be a reference type.where T : new()
: Specifies that the type parameter must have a parameterless constructor.where T : SomeBaseClass
: Specifies that the type parameter must be a subclass ofSomeBaseClass
.where T : ISomeInterface
: Specifies that the type parameter must implementISomeInterface
.
Example:
csharppublic class ConstraintExample<T> where T : new()
{
public T CreateInstance()
{
return new T(); // Requires T to have a parameterless constructor
}
}
5. Generic Collections
C# provides several generic collections in the System.Collections.Generic
namespace, such as List<T>
, Dictionary<TKey, TValue>
, and Queue<T>
.
Example with List<T>
:
csharpList<string> names = new List<string>
{
"Alice",
"Bob",
"Charlie"
};
names.Add("Dave");
foreach (string name in names)
{
{
Console.WriteLine(name); // Prints each name
}
Example with Dictionary<TKey, TValue>
:
csharpDictionary<string, int> ages = new Dictionary<string, int>
{
{ "Alice", 30 },
{ "Bob", 25 }
};
ages["Charlie"] = 35;
foreach (var entry in ages)
{
{
Console.WriteLine($"{entry.Key}: {entry.Value}"); // Prints name and age
}
6. Covariance and Contravariance
Covariance and contravariance apply to generic interfaces and delegates and allow for more flexibility in type assignment.
- Covariance allows a method to return a more derived type than originally specified.
- Contravariance allows a method to accept parameters of a less derived type.
Example with Interfaces:
csharppublic interface ICovariant<out T>
{
T GetValue();
}
public interface IContravariant<in T>
{
void SetValue(T value);
}
public class StringCovariant : ICovariant<string>
{
public string GetValue()
{
return "Hello";
}
}
public class ObjectContravariant : IContravariant<object>
{
public void SetValue(object value)
{
Console.WriteLine(value);
}
}
Summary
Generics in C# provide a way to create reusable and type-safe code by defining classes, interfaces, and methods with placeholder types. They enhance code flexibility and maintainability by allowing you to work with different data types without sacrificing type safety. Constraints, generic collections, and concepts like covariance and contravariance further extend the capabilities and flexibility of generics. Understanding and using generics effectively can significantly improve your coding efficiency and reduce code duplication.