Skip to content

Delegate covariance and contravariance C# 2.0code reductionreadability

Allow a delegate to point at a method whose parameters or return type are less or more derived than the delegate's signature.

A delegate type declares an exact signature, but a method with a compatible but not identical signature is often what you have. Before C# 2.0 a delegate could only be bound to a method whose return type and parameter types matched exactly, so a method returning Dog could not be assigned to a delegate returning Animal.

C# 2.0 adds variance to delegate binding. A delegate can reference a method with:

  • A less derived return type than the delegate declares - covariance
  • More derived parameter types than the delegate declares - contravariance

Code ​

csharp
delegate Animal AnimalFactory();
delegate void DogHandler(Dog dog);

static Dog CreateDog() => new Dog();
static void HandleAnimal(Animal animal) => animal.Feed();

// Covariance: returns Dog, delegate wants Animal
AnimalFactory factory = CreateDog;

// Contravariance: takes Animal, delegate wants Dog
DogHandler handler = HandleAnimal;
csharp
// A wrapper method was needed to bridge the signature gap
AnimalFactory factory = new AnimalFactory(delegate { return CreateDog(); });
DogHandler handler = new DogHandler(delegate (Dog dog) { HandleAnimal(dog); });

Notes ​

  • Names line up with generic variance: a delegate's return type is an output position, so it is covariant, and its parameters are input positions, so they are contravariant
  • Only reference types participate. A method returning int cannot bind to a delegate returning object, because that would require boxing
  • This applies to method group conversion too, which is why Func<object> can be assigned a method returning string without a wrapper lambda
  • Related: generic covariance C# 4.0 and generic contravariance C# 4.0 extend the same rules to generic type arguments, which is a separate mechanism that arrived later
  • See anonymous methods C# 2.0 for the delegate syntax used in the before example

More information ​

Powered by Intracia