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>
to IEnumerable<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>
to IEnumerable<object>
for example.) It also only works where it makes sense - IEnumerable<T>
is covariant as objects only come "out" of the API, whereas IList<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>
to IComparer<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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With