Contravariance (`in`) in Generic Interfaces & Delegates
1Concept
Contravariance (`in T`) allows assigning a less derived type parameter to a more derived interface (`IComparer<object>` -> `IComparer<string>`). Contravariant type parameters can only appear as input arguments.
2Architecture Diagram
Inheritance: string (Derived) ──> object (Base) Contravariance (`in T`): IComparer<object> (Base) ──────────> Can assign to ──────────> IComparer<string> (Derived)
3Code Example
C# 13 & .NET 9
using System;
using System.Collections.Generic;
public class ObjectLengthComparer : IComparer<object>
{
public int Compare(object? x, object? y)
{
return (x?.ToString()?.Length ?? 0).CompareTo(y?.ToString()?.Length ?? 0);
}
}
public class ContravarianceDemo
{
public static void Main()
{
// IComparer<in T> is contravariant: can assign IComparer<object> to IComparer<string>
IComparer<string> strComparer = new ObjectLengthComparer();
int cmp = strComparer.Compare("Microservices", "API");
Console.WriteLine($"Comparison Result: {cmp}");
}
}4Expected Output
Comparison Result: 1
5Key Takeaways
- ✓`in T` marks a type parameter as contravariant (consumer only).
- ✓`Action<in T>`, `IComparable<in T>`, and `IComparer<in T>` are contravariant.
- ✓Variance applies strictly to reference types.