Covariance and Contravariance

There are two important delegate features. What we have learned so far is that normally, to register a method in a delegate, the method has to match the signature of the delegate. This means that the return type and the parameters of the method and the delegate have to be the same. However, with the use of the concepts of covariance and contravariance, you can actually register methods to a delegate that don't have the same return types or parameters. The delegate will then be able to execute them when called. 

Covariance is when you assign a method to a delegate that has a return type that is a derived type of the delegate's return type. For example, if class B is derived from class A, and if the delegate returns class A, then a method can be registered to the delegate that returns class B. Let's look at the example in the following code:

using System;

namespace EventsAndDelegates
{
public delegate A DoSomething();

public class A
{
public int value { get; set; }
}

public class B : A {}


public class Program
{
public static A WorkA()
{
A a = new A();
a.value = 1;
return a;
}

public static B WorkB()
{
B b = new B();
b.value = 2;
return b;
}

public static void Main(string[] args)
{
A someA = new A();

DoSomething something = WorkB;

someA = something();

Console.WriteLine("The value is " + someA.value);

Console.ReadLine();
}
}
}

The output of the preceding code will be as follows:

On the other hand, contravariance is when a method is passed to a delegate and the parameters of the method don't match the parameters of the delegate. Here, we have to keep in mind that the parameter type of the method has to be at least derived from the parameter type of the delegate. Let's look at an example of contravariance:

using System;

namespace EventsAndDelegates
{
public delegate int DoSomething(B b);

public class A
{
public int value = 5;
}

public class B : A {}


public class Program
{
public static int WorkA(A a)
{
Console.WriteLine("Method WorkA called: ");
return a.value * 5;
}

public static int WorkB(B b)
{
Console.WriteLine("Method WorkB called: ");
return b.value * 10;
}


public static void Main(string[] args)
{
B someB = new B();

DoSomething something = WorkA;

int result = something(someB);

Console.WriteLine("The value is " + result);

Console.ReadLine();
}
}
}

The preceding code will give the following output:

Here, we can see that the delegate takes type B as a parameter. However, when the WorkA method had been registered as a method in the delegate, it didn't give any error or warning, even though the parameter that WorkA method takes is type A. The reason why it works is because type B is derived from type A.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.44.199