Generics

Intro

Generics let you write type-safe, reusable code without duplicating logic per type. Instead of accepting object and casting later, you keep strong compile-time guarantees and better IDE support. In .NET, generics also matter for performance because collections like List<int> avoid boxing that older non-generic APIs caused.

Use Cases

Constraints

Constraints define what operations are legal on T and protect APIs from invalid type arguments.

Variance

Variance controls assignment compatibility between constructed generic types.

IEnumerable<string> names = new List<string> { "Ada", "Linus" };
IEnumerable<object> objects = names; // covariance

Action<object> printAny = o => Console.WriteLine(o);
Action<string> printString = printAny; // contravariance

List<string> list = new();
// List<object> invalid = list; // does not compile (invariance)

Example

public static T CreateAndValidate<T>()
    where T : EntityBase, IValidatable, new()
{
    var value = new T();
    value.Validate();
    return value;
}

Pitfalls

Tradeoffs

Questions


Whats next