I have an interface defined as below:
public interface TestInterface{
int id { get; set; }
}
And two Linq-to-SQL classes implementing that interface:
public class tblTestA : TestInterface{
public int id { get; set; }
}
public class tblTestB : TestInterface{
public int id { get; set; }
}
I have IEnumerable lists a and b populated by the database records from tblTestA and tblTestB
IEnumerable<tblTestA> a = db.tblTestAs.AsEnumerable();
IEnumerable<tblTestB> b = db.tblTestBs.AsEnumerable();
However, the following is not permitted:
List<TestInterface> list = new List<TestInterface>();
list.AddRange(a);
list.AddRange(b);
I have to do as follows:
foreach(tblTestA item in a)
list.Add(item)
foreach(tblTestB item in b)
list.Add(item)
Is there something I am doing wrong? Thanks for any help
This works in C# 4, due to generic covariance. Unlike previous versions of C#, there is a conversion from
IEnumerable<tblTestA>toIEnumerable<TestInterface>.The functionality has been in the CLR from v2, but it’s only been exposed in C# 4 (and the framework types didn’t take advantage of it before .NET 4 either). It only applies to generic interfaces and delegates (not classes) and only for reference types (so there’s no conversion from
IEnumerable<int>toIEnumerable<object>for example.) It also only works where it makes sense –IEnumerable<T>is covariant as objects only come "out" of the API, whereasIList<T>is invariant because you can add values with that API too.Generic contravariance is also supported, working in the other direction – so for example you can convert from
IComparer<object>toIComparer<string>.If you’re not using C# 4, then Tim’s suggestion of using
Enumerable.Cast<T>is a good one – you lose a little efficiency, but it will work.If you want to learn more about generic variance, Eric Lippert has a long series of blog posts about it, and I gave a talk about it at NDC 2010 which you can watch on the NDC video page.