Phase 9 of 30 · Topic 9.4

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.