New Features in C# 2.0—Co- and Contravariance: What just happened?

Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio


Jump to: navigation, search
CSharp-Online.NET:Tutorials
C# Tutorials

New Features in C# 2.0

© 2005 O'Reilly Media, Inc.

What just happened?

The Program class in Example 1-10 declares two delegates. The first is for a method that takes no parameters and returns a Mammal:

public delegate Mammal theCovariantMethod( );

In the run method, you declare an instance of Mammal and an instance of Dog:

Mammal m = new Mammal();
Dog d = new Dog();


Earlier in the file you declared Dog to derive from Mammal.


You are ready to create your first instance of theCovariantDelegate:

theCovariantDelegate myCovariantDelegate =
  new theCovariantDelegate(m.ReturnsMammal);

This matches the delegate signature (m.ReturnsMammal( ) is a method that takes no parameters and returns a Mammal), so you can invoke the method through the delegate:

myCovariantDelegate( );

Now you use covariance to encapsulate a second method within the same delegate:

myCovariantDelegate =
  new theCovariantDelegate(d.ReturnsDog);

This time, however, you are passing in a method (d.ReturnsDog( )) that does not return a Mammal; it returns a Dog that derives from Mammal:

public Dog ReturnsDog( )
{
  Console.WriteLine("Returning a dog");
  return this;
}

That is covariance at work. To see contravariance, you declare a second delegate to encapsulate a method that returns null and takes a Dog as a parameter:

public delegate void theContravariantDelegate(Dog theDog);

Your first instantiation of this delegate encapsulates a method with the appropriate return value (void) and parameter (Dog):

myContravariantDelegate =
new theContravariantDelegate(MyMethodThatTakesADog);


Notice that with contravariance, you can pass in an object of the base type as a parameter where an object of the derived type is expected.


You can invoke the method through the delegate. Your second use of this delegate, however, encapsulates a method that does not take a Dog as a parameter, but rather, takes a Mammal as a parameter:

theContravariantDelegate myContravariantDelegate =
  new theContravariantDelegate(MyMethodThatTakesAMammal);

MyMethodThatTakesAMammal is defined to take a Mammal, not a Dog, as a parameter:

private void MyMethodThatTakesAMammal(Mammal theMammal)
{
  Console.WriteLine("in My Method That Takes A Mammal");
}

Again, this works because a Dog is a Mammal and contravariance allows you to make this substitution.


Previous_Page_.gif Next_Page_.gif


Personal tools