C# › Generics

How do generic attributes (introduced in C# 11) work, and what limitation did they finally remove compared to older attribute usage patterns?

Advanced

Answer

Prior to C# 11, an attribute class couldn't itself be generic (`public class MyAttribute<T> : Attribute` was disallowed), forcing awkward workarounds like passing a Type object as a constructor argument instead; C# 11 allows genuinely generic attribute classes, letting you specify the type argument directly and get compile-time type checking on the attribute's type parameter.
// C# 11+: genuinely generic attribute
public class ValidatorAttribute<T> : Attribute where T : IValidator { }

[Validator<EmailValidator>] // type-checked at compile time
public string Email { get; set; } = "";

// Older workaround before C# 11:
// [Validator(typeof(EmailValidator))] -- no compile-time type constraint enforcement
Real-world example Writing a strongly-typed validation attribute that references a specific validator TYPE with full compile-time type checking.

Common follow-ups: Why couldn't older C# express this same idea with full type safety before generic attributes were introduced?