You are here

Covariance and contravariance in C#


namespace CovarianceContravarianceTest
{
    class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public void PrintStuff()
        {
            Console.WriteLine("FirstName = {0}, LastName = {1}", FirstName, LastName);            
        }
    }

    class Employee : Person 
    {
        public int ID { get; set; }
        public void InitBaseClass(Person p)
        {
            //Though not perfect way to init base class but it is here for testing properties
            foreach(var prop in typeof(Person).GetProperties())
            {
                this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(p, null), null);
            }
        }

        public new void  PrintStuff()
        {
            Console.WriteLine("ID = {0}", ID);
            base.PrintStuff();
        }
    }

    class Program
    {
        //Covariance return type is base class but in actuall class it can return subclass
        private delegate Person ReturnPersonDelegate();
        private static ReturnPersonDelegate PersonReturnDel;

        //Contravariance parameter type is super class class but in actuall class it can use derived class
        private delegate void ParameterPersonDelegate(Employee  em);
        private static ParameterPersonDelegate PersonParameterDel;

        static void Main(string[] args)
        {
            PersonReturnDel = new ReturnPersonDelegate(ReturnEmployeeType);
            Person p = PersonReturnDel.Invoke();
            p.PrintStuff();

            Employee em = new Employee() { ID = 1 };
            em.InitBaseClass(p);

            PersonParameterDel  = new ParameterPersonDelegate(UsePersonTypeParameter);
            PersonParameterDel.Invoke(em);
            Console.ReadKey();
        }

        //We are returning Employee type that is derive class from Person
        //IN delegate declaration we have base class this is  Covariance
        static Employee ReturnEmployeeType()
        {
            Person p = new Person() { FirstName = "Mahbub", LastName = "Rahman" };
            Employee em = new Employee() {ID = 200};
            em.InitBaseClass(p);
            return em;
        }

        // In deligate it is specified as Employee but we are passing base class 
        // This is Contravariance
        static void UsePersonTypeParameter(Person pe)
        {
            Employee em =(Employee) pe;
            em.PrintStuff();
        }
    }
}