Covariant Generic List

The other day I was working with some generic lists of some custom classes.

All of these classes inherited from a common base class.

I wanted to write a method where I could pass any of my generic lists to this method and iterate over the list and execute some other code.

I thought this was a perfect example for passing a generic type into my method. I tried everything I know and could not get this to work.

I posted a question on the MSDN forums about my problem and John Grove pointed me at this article.

So it turns out what I was wanting was a Covariant Generic List.

I pretty much followed what was outlined in the article, but I will document here what I exactly did, namely because I had a hard time finding the solution to this problem.

This starts off by defining a interface for our base class.

public interface IClassInterface
{
   string Property1 { get; set; }
   string Property2 { get; set; }
}
Then we have to define our base class, plus any class that
inherits from it.
public class ClassA : IClassInterface
{
   public ClassA() {}
   
   public ClassA(ClassA objectA)
   {
      this.Property1 = objectA.Property1;
      this.Property2 = objectA.Property2;
   }

   public ClassA(string property1, string property2)
   {
      this.Property1 = property1;
      this.Property2 = property2;
   }

   public string Property1
   {
       get; set;
   }

   public string Property2
   {
       get; set;
   }
}

public class ClassB : ClassA
{
    public ClassB() {}

    public ClassB(ClassA objectA, string property3, string property4)
                             : base(objectA)
    {
       this.Property3 = property3;
       this.Property4 = property4;           
    }

    public string Property3
    {
       get; set;
    }

    public string Property4
    {
       get; set;
    }
}
Next we define a class that a returns enumerable generic list.
public class EnumerableGeneric<TClass, TInterface> 
              : IEnumerable<TInterface> where TClass : TInterface
{
   private IList<TClass> list;

   public EnumerableGeneric(IList<TClass> list)
   {
      this.list = list;
   }

   public IEnumerator<TInterface> GetEnumerator()
   {
      foreach (TClass item in list)
      {
         yield return item;
      }
   }

   IEnumerator IEnumerable.GetEnumerator()
   {
      return this.GetEnumerator();
   }
}
Next we define our method that we are going to use to perform
 some operation on each of the lists.
private void MyMethod(IEnumerable<IClassInterface> genericList)
{
   foreach (IClassInterface classVariable in genericList)
   {
      // Other code goes here.
   }
}
And finally we create our lists, populate some data and call our method.
List<ClassA> caInstance = new List<ClassA>();

caInstance.Add(new ClassA("A", "B"));
caInstance.Add(new ClassA("C", "D"));

List<ClassB> cbInstance = new List<ClassB>();
cbInstance.Add(new ClassB(new ClassA("E", "F"), "G", "H"));
cbInstance.Add(new ClassB(new ClassA("I", "J"), "K", "L"));

MyMethod(new EnumerableGeneric<ClassA, IClassInterface>(caInstance));

MyMethod(new EnumerableGeneric<ClassB, IClassInterface>(cbInstance));


I appreciate John Grove for taking the time on the MSDN forums to answer my question and also to Stefan Delmarco for posting the original article.

Hope this helps somebody else, I know it helped me.

 

Published Sunday, April 19, 2009 8:47 PM by dmccollough

Comments

# re: Covariant Generic List

Sunday, April 19, 2009 10:40 PM by Joe Chung

Thankfully, you won't have to jump through these hoops in .NET 4.0 where covariance and contravariance will be supported in the framework.  Watch Anders Hejlsberg's Lang.NET Symposium lightning talk video on the topic for a brief overview:

www.langnetsymposium.com/.../11-AndersHejlsberg-LightningCovariantContravariant.html

# re: Covariant Generic List

Monday, April 20, 2009 12:10 AM by Bill McCarthy

wouldn't it be simpler to use LINQ, eg:

MyMethod(caInstance.Select(x => (IClassInterface)x));

or:

MyMethod(caInstance.Cast<IClassInterface>());

etc.

# re: Covariant Generic List

Monday, April 20, 2009 7:56 AM by dmccollough

Yes, it looks like it would be easier to user LINQ. Thanks for the tip.

# re: Covariant Generic List

Monday, April 20, 2009 3:32 PM by JD

Why couldn't you just write your method as a generic method? Something like this:

private void MyMethod<T>(IList<T> genericList) where T : MyBaseClass {...}

You'd still get access to all the methods of your base class and avoid a lot of gyrations.

# re: Covariant Generic List

Monday, April 20, 2009 7:11 PM by dmccollough

I will certainly give this a try. I'm always looking for a simpler method.

# Iterators: a flag for simplification ?

Monday, April 20, 2009 10:02 PM by @ Head

A couple of months ago I blogged about iterators in VB (or the lack there-of), and pointed folks to an