Link to home
Start Free TrialLog in
Avatar of milani_lucie
milani_lucieFlag for United States of America

asked on

Covariance and Contravariance in Delegates examples needed in C#

Hi,

Can you please provide end-to-end examples in C# on:

Covariance and Contravariance in Delegates

Thanks
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

As luck would have it, MSDN has an article that's actually titled "Covariance and Contravariance in Delegates", with code examples. http://msdn.microsoft.com/en-us/library/ms173174(v=vs.80).aspx

Is that explanation enough, or something there not making sense?
Avatar of milani_lucie

ASKER

I hate MSDN. Here is the nice article:

http://codebetter.com/raymondlewallen/2006/12/28/covariance-and-contravariance/

Can you please provide complete code for both of them ?

Thanks
Well, both articles seem to already include complete code examples of both covariance and contravariance, so I guess I'm not sure what more you want...?

I'll try and think of a real-world example, but after having just read those two articles I suspect anything I come up with is going to end up being about the same examples in the articles, just paraphrased. ;)
This is the code i am having:

public class Car
{
      private string m_Model;

      public string Model
      {
           get
           {
                  return m_Model;
           }
           set
          {
                  m_Model = value;
          }              
      }
}

public class Toyota : Car
{
      private string m_Color;

      public string Color
      {
           get
           {
                  return m_Color;
           }
           set
          {
                  m_Color = value;
          }              
      }
}

class Demo
{
    public delegate Car MyMethod();

    public static Car FunctionOne()
    {
        return new Car();
    }
 
    public static Toyota FunctionTwo()
    {
        return new Toyota();
    }

    static void Main()
    {
        MyMethod abc = FunctionOne;
        MyMethod xyz = FunctionTwo;
    }

   //  Now what ? What we can do ?

}

Thanks
ASKER CERTIFIED SOLUTION
Avatar of Mathiyazhagan
Mathiyazhagan
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Mathiyazhagan:

Excellent ! Can you please provide me for contravarience also ? Here is the code i do have:

    public class Car
    {
        private int m_Price;

        public int Price
        {
            get
            {
                return m_Price;
            }
            set
            {
                m_Price = value;
            }
        }

        public virtual void Print()
        {
            Console.WriteLine("Price : {0}", m_Price);
        }
    }

    public class Toyota : Car
    {
        private string m_Model;

        public string Model
        {
            get
            {
                return m_Model;
            }
            set
            {
                m_Model = value;
            }
        }
       
        public override void Print()
        {
            Console.WriteLine("Price : {0}, Model : {1}", base.Price, m_Model);
        }
    }

    public delegate void GetVechicle(Toyota value);

    public static void GetCar(Car value)
        {  
            Car c = value;
            c.Price = 4000;
            return c;
        }

        public static void GetToyota(Toyota value)
        {
            Toyota t = value;
            t.Price = 5000;
            t.Model = "Corolla";
            return t;
        }

Can you please provide the sample code for this also ?

Thanks
Okay, first a quick word on the definition of covariance and contravariance.  In very simple terms covariance is conversion from a wider (or base) type to a narrower (or derived type); and contravariance is the opposite - a conversion from a narrower (or derived) type to a wider (or base) type.


Given this simple example, with two classes.  Mammals being the wider, or less-derived, of the two (it serves as the base class for Dog), and Dog, which inherits from Mammals, is the narrower (or more derived).
using System;

class Program
{
	static void Main(string[] args)
	{
		// Declare a variable of a "wide" or less-derived type
		Mammals mammalObject = new Mammals();

		// Declare a variable of a "narrow" or more-derived type
		Dog dogObject;

		// Assigning the mammalObject to a narrower, or more derived, type is covariance
		// Casting the less derived mammalObject to a more derived type of "Dog" is an
		// example of covariance
		// Note that C# doesn't allow this type of covariance for classes, I'm just trying
		// to demonstrate a concept.
		dogObject = (Dog)mammalObject;


		// The opposite is contravariance (which is permissable in C# for classes)
		// Assign a new Dog object to the more derived (or narrower) variable
		dogObject = new Dog();

		// Cast the narrower dogObject to the wider type Mammal, and assign it
		// to the mammalObject variable
		mammalObject = (Mammals)dogObject;
	}
}

// Mammals is the base class
class Mammals
{
}

// Dog inherits from Mammals, so it is said to be "derived" (and Mammals is "less derived")
class Dog : Mammals
{
}

Open in new window



As far as delegates go, I'm going to refer you to the examples in the MSDN article. Perhaps this commented version of that example will make more sense (sorry, I still can't seem to come up with a real-world example of this):
using System;

class Program
{
	// Define a delegate that will point to a method which takes no
	// parameters and returns an object of type "Mammals"
	delegate Mammals MyMammalsDelegate();

	// Define a method that takes no parameters
	// and returns a Dog object
	static Dog MyDogMethod()
	{
		return new Dog();
	}

	static void Main(string[] args)
	{
		// Declare a variable of type "MyMammalsDelegate"
		MyMammalsDelegate theDelegate;

		// Assign the method "MyDogMethod" to "theDelegate"
		// even though the MyDogMethod returns a "Dog" object,
		// and the MyMammalsDelegate expects a method that returns
		// a Mammals object, covariance in delegates allows this
		// This is covariance because theDelegate is defined with the return type "Mammals"
		// so we'll say theDelegate is a Mammals variable, and MyDogMethod is defined with
		// the return type Dog, so we'll say MyDogMethod is a Dog variable (not really, just for the sake of explanation),
		// so we're assigning a Dog object to a Mammals object, which is assigning
		// a narrower type to a wider type
		theDelegate = MyDogMethod;
	}
}

// Mammals is the base class
class Mammals
{
}

// Dog inherits from Mammals, so it is said to be "derived" (and Mammals is "less derived")
class Dog : Mammals
{
}

Open in new window




Contravariance I can see some practical application for...see the comments in code.
// These classes are actually defined in the .Net Framework, so 
// they are commented-out - these comments are included here
// to make obvious their inheritance relationship to each other
/*
class EventArgs // Base EventArgs Class
{
}

class KeyEventArgs : EventArgs // Derived class that inherits from EventArgs
{
}

class MouseEventArgs : EventArgs // Another derived class, that also inherits from EventArgs
{
}
*/

public partial class Form1 : Form
{
	public Form1()
	{
		InitializeComponent();

		// The KeyDown event expects a KeyEventHandler method,
		// which accepts a KeyEventArgs as a parameter, so we'll
		// say this.KeyDown is a KeyEventArgs (again, not really, just for explanation).
		// We are assigning it a method that takes a EventArgs object, so we'll say
		// MultiEventHandler is a EventArgs.  Since KeyEventArgs inherits from
		// EventArgs, we are assigning the wider (or less-derived, or base) type EventArgs
		// to the narrower (or more-derived) type EventArgs, this is conravariance
		this.KeyDown += MultiEventHandler;

		// The practical application of this being, for example, that
		// completely different events can share the same event handler
		// Here the MouseClick event expects a method that takes a MouseEventArgs
		// as a parameter, but because MouseEventArgs also inherits from EventArgs,
		// we can use the MultiEventHandler method.
		this.MouseClick += MultiEventHandler;
	}

	private void MultiEventHandler(object sender, EventArgs e)
	{
		if (e is KeyEventArgs)
			MessageBox.Show("This method running as result of Form1's KeyDown event.");
		else if (e is MouseEventArgs)
			MessageBox.Show("This method running as result of Form1's MouseClick event.");
	}
}

Open in new window

Mathiyazhagan: / tgerbert:

Here is the sample code i am having. Can you please complete the code ? It is throwing some errors.

namespace ConsoleApplication1
{
    class Program
    {
        private delegate void GetVechicle(Car c);

        public static void GetCar(Car c)
        {
            c.Price = 4000;
        }

        public static void GetToyota(Toyota t)
        {
            t.Price = 5000;
            t.Model = "Corolla";
        }

        static void Main(string[] args)
        {
            GetVechicle v1 = GetCar;
            GetVechicle v2 = GetToyota;

            Corolla c = new Corolla();

            v1.Invoke(c);
            v2.Invoke(c);

            c.Print();
        }
    }

    public class Car
    {
        private int m_Price;

        public int Price
        {
            get
            {
                return m_Price;
            }
            set
            {
                m_Price = value;
            }
        }

        public virtual void Print()
        {
            Console.WriteLine("Price : {0}", m_Price);
        }
    }

    public class Toyota : Car
    {
        private string m_Model;

        public string Model
        {
            get
            {
                return m_Model;
            }
            set
            {
                m_Model = value;
            }
        }

        public override void Print()
        {
            Console.WriteLine("Price : {0}, Model : {1}", base.Price, m_Model);
        }
    }

    public class Corolla : Toyota
    {
        private string m_Color;

        public string Color
        {
            get
            {
                return m_Color;
            }
            set
            {
                m_Color = value;
            }
        }

        public override void Print()
        {
            Console.WriteLine("Price : {0}, Model : {1}, Color : {2}", base.Price, base.Model, m_Color);
        }
    }
}

Thanks
What exception, and on what line?
Sorry .... Here is the complete code:

namespace ConsoleApplication1
{
    class Program
    {
        private delegate void GetVechicle(Toyota t);

        public static void GetCar(Car c)
        {
            c.Price = 4000;
        }

        public static void GetToyota(Toyota t)
        {
            t.Price = 5000;
            t.Model = "Corolla";
        }

        static void Main(string[] args)
        {
            GetVechicle v1 = GetCar;
            GetVechicle v2 = GetToyota;

            Toyota t = new Toyota();

            v1.Invoke(t);
            v2.Invoke(t);

            t.Print();
        }
    }

    public class Car
    {
        private int m_Price;

        public int Price
        {
            get
            {
                return m_Price;
            }
            set
            {
                m_Price = value;
            }
        }

        public virtual void Print()
        {
            Console.WriteLine("Price : {0}", m_Price);
        }
    }

    public class Toyota : Car
    {
        private string m_Model;

        public string Model
        {
            get
            {
                return m_Model;
            }
            set
            {
                m_Model = value;
            }
        }

        public override void Print()
        {
            Console.WriteLine("Price : {0}, Model : {1}", base.Price, m_Model);
        }
    }
}

I want to do something like this as like in the above example:

List<Car> cars = new List<Car>();  
cars.Add(v1.Invoke());  
cars.Add(v2.Invoke());  
foreach (Car c in cars )  
{  
      c.Print();  
}  

Can you please provide me the code ?

Thanks
The List<Car>.Add() method expects you to provide a Car object. Your v1 and v2 point to methods that don't return anything (their return type is "void"), you need to use a method that returns a Car object.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

class Program
{
	// Declare a delegate that will point to a function
	// which will return a Car object
	delegate Car GetVehicleDelegate();

	// Define a method that returns a Car object
	static Car GetCarMethod()
	{
		Car c = new Car();
		c.Price = 4000;
		return c;
	}

	// Define a method that returns a Toyota object
	static Toyota GetToyotaMethod()
	{
		Toyota t = new Toyota();
		t.Price = 5000;
		t.Model = "Corolla";
		return t;
	}

	static void Main(string[] args)
	{
		// Declare a variable that's of the type GetVehicleDelegate,
		// which means it will point to a method that returns a Car
		GetVehicleDelegate getCar = GetCarMethod;

		// Declare another variable that's of type GetVehicleDelegate,
		// but instead of assigning it a method that returns a Car,
		// assign it a method that returns a Toyota. Covariance
		// allows this mismatch of return types because Toyota
		// inherits from Car
		GetVehicleDelegate getToyota = GetToyotaMethod;

		List<Car> cars = new List<Car>();

		cars.Add(getCar.Invoke());
		cars.Add(getToyota.Invoke());

		foreach (Car c in cars)
			Console.WriteLine(c);

		Console.ReadKey();
	}
}

public class Car
{
	private int _price;
	public int Price
	{
		get { return _price; }
		set { _price = value; }
	}
	public override string ToString()
	{
		return String.Format("Car, price: {0}", _price);
	}
}

public class Toyota : Car
{
	private string _model;
	public string Model
	{
		get { return _model; }
		set { _model = value; }
	}
	public override string ToString()
	{
		return String.Format("Toyota, price: {0}, model: {1}", this.Price, _model);
	}
}

Open in new window

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial