Generics allow you to write code that works with any type while maintaining 100% type safety. This eliminates the need for "Object" casting and prevents the performance penalty of Boxing and Unboxing.
Instead of creating IntRepository, StringRepository, etc., you create ONE repository that takes a type T.
public class Repository<T>
{
private List<T> _data = new();
public void Add(T item) => _data.Add(item);
}
What if your repository ONLY works for classes that have a database ID? You use where constraints to restrict which types can be used.
public class BaseEntity { public int Id { get; set; } }
// T MUST be a class, MUST have a parameterless constructor,
// and MUST inherit from BaseEntity.
public class SecureRepo<T> where T : BaseEntity, new()
{
public void LogId(T item) => Console.WriteLine(item.Id);
}
Because the compiler generates a specific version of your class for every value type (like int), generics are significantly faster than using object. No casting is required, and no memory is wasted.
Q: "What is Variance (Covariance and Contravariance) in Generics?"
Architect Answer: "Variance defines whether you can use a more derived type (Covariance) or a more generic type (Contravariance) than originally specified. In C#, we use the `out` and `in` keywords on interfaces. `IEnumerable