Archive

Posts Tagged ‘Covariance’

Covariance in C#

February 28, 2011 1 comment

We are going to have a quick look at covariance in C#.

Only elements that can be covariant:

  • Interfaces
  • Delegates

Convariance is similar to Inheritance in the sense that if you have a class like IEnumerable which is covariant then you can assign a subclass of IEnumerable to IEnumerable.

Example: Base Person, Sub Class is Student. With Covariance you can assign IEnumerable to IEnumerable

You would just naturally think this would work but is has not until .NET 4 was introduced.

To allow convariance you must mark the generic parameter as out T as shown below in IIterable and IIterator. I wrote my own iterator design pattern based classes below to illustrate this.

you can only assign using references as shown in the main method. Assigning to base classes not interfaces won’t work.

using System;
using System.Collections.Generic;

namespace Variance
{


    public abstract class Entity<TKey> : IEquatable<Entity<TKey>>
    {

        public TKey Id { get; set; }

        protected Entity()
        {
            Id = default(TKey);
        }

        protected Entity(TKey identity)
        {
            Id = identity;
        }

        public override bool Equals(object obj)
        {
            var entity = obj as Entity<TKey>;
            return Equals(entity);
        }

        public bool Equals(Entity<TKey> other)
        {
            return other != null && Equals(Id, other.Id);
        }

        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }
    }

    public class Person : Entity<int>
    {
        public string Name { get; set; }

        public override string ToString()
        {
            return String.Format("{0} - {1}", Id, Name);
        }
    }

    public class Student : Person
    {
        public string Course { get; set; }
    }

    public interface IIterator<out T>
    {
        bool HasMoreElements { get; }
        T Current { get; }
        void Continue();
    }

    public interface IIterable<out T>
    {
        IIterator<T> GetIterator();
    }

    public class BasicList<T> : IIterable<T>
    {

        protected List<T> Items = new List<T>();

        public void AddItem(T item)
        {
            Items.Add(item);
        }

        public IIterator<T> GetIterator()
        {
            return new BlIterator<T>(Items);
        }

        public void PrinttoConsole()
        {
            foreach (var item in Items)
            {
                Console.WriteLine(item);
            }
        }

        public class BlIterator<T> : IIterator<T>
        {

            protected List<T> items = new List<T>(); 

            public BlIterator(List<T> items)
            {
                this.items = items;
            }

            private int index;

            public bool HasMoreElements
            {
                get { return index <= items.Count - 1; }
            }

            public T Current
            {
                get { return items[index]; }
            }

            public void Continue()
            {
                index++;
            }
        }


    }

    class Program
    {

        

        static void Main()
        {

            IIterable<Student> students = GetStudents();

            Print(students); // Covariance



            IIterable<Person> people = students; // Covariance

            Print(people);

            Console.WriteLine("Press any key to exit...");
            Console.ReadLine();
        }

        public static IIterable<Student> GetStudents()
        {
            BasicList<Student> students = new BasicList<Student>();
            students.AddItem(new Student { Id = 1, Name = "Blair" });
            students.AddItem(new Student { Id = 2, Name = "Tim" });
            students.AddItem(new Student { Id = 3, Name = "Tom" });
            return students;
        }

        public static void Print(IIterable<Person> print) // Covariance
        {

            var iterator = print.GetIterator();

            while (iterator.HasMoreElements)
            {
                Console.WriteLine(iterator.Current);
                iterator.Continue();
            }
        }
    }
}

Blair…

Advertisements