c#Linq`List <Interface> .AddRange`方法不起作用

Jim*_*mbo 7 c# linq addrange

我有一个定义如下的接口:

public interface TestInterface{
    int id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

两个实现该接口的Linq-to-SQL类:

public class tblTestA : TestInterface{
    public int id { get; set; }
}

public class tblTestB : TestInterface{
    public int id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我有来自tblTestA和tblTestB的数据库记录填充的IEnumerable列表a和b

IEnumerable<tblTestA> a = db.tblTestAs.AsEnumerable();
IEnumerable<tblTestB> b = db.tblTestBs.AsEnumerable();
Run Code Online (Sandbox Code Playgroud)

但是,不允许以下内容:

List<TestInterface> list = new List<TestInterface>();
list.AddRange(a);
list.AddRange(b);
Run Code Online (Sandbox Code Playgroud)

我必须做如下:

foreach(tblTestA item in a)
    list.Add(item)

foreach(tblTestB item in b)
    list.Add(item)
Run Code Online (Sandbox Code Playgroud)

有什么我做错了吗?谢谢你的帮助

Jon*_*eet 9

由于通用协方差,这适用于C#4 .与以前版本的C#不同,有一个转换IEnumerable<tblTestA>IEnumerable<TestInterface>.

该功能已经在v2的CLR中进行,但它仅在C#4中公开(并且框架类型在.NET 4之前也没有利用它).它适用于只为引用类型的通用接口和委托(而不是类)(所以没有转换,从IEnumerable<int>IEnumerable<object>的例子.)它也只能在有意义- IEnumerable<T>是协变的对象只来"走出去"的API,虽然IList<T>不变的,因为您也可以使用该API添加值.

支持通用逆变,在另一个方向工作 - 例如,您可以转换IComparer<object>IComparer<string>.

如果你没有使用C#4,那么蒂姆的使用建议Enumerable.Cast<T>很好 - 你会失去一点效率,但它会起作用.

如果您想了解有关泛型差异的更多信息,Eric Lippert有很多关于它的博客文章,我在NDC 2010 上发表了一篇关于它的讨论,您可以在NDC视频页面上观看.


Tim*_*son 6

你没有做错什么:List<TestInterface>.AddRange期待一个IEnumerable<TestInterface>.它不会接受IEnumerable<tblTestA>IEnumerable<tblTestB>.

你的foreach循环工作.或者,您可以使用Cast更改类型:

List<TestInterface> list = new List<TestInterface>();
list.AddRange(a.Cast<TestInterface>());
list.AddRange(b.Cast<TestInterface>());
Run Code Online (Sandbox Code Playgroud)