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.