Home > Development > Covariance in C#

Covariance in C#


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
  1. March 4, 2011 at 5:12 pm

    interesting find, I’ll share it

    post again!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: