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

public interface TestInterface{
    int id { get; set; }
}

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

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

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

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

IEnumerable<tblTestA> a = db.tblTestAs.AsEnumerable();
IEnumerable<tblTestB> b = db.tblTestBs.AsEnumerable();

但是,以下是不允许的:

List<TestInterface> list = new List<TestInterface>();
list.AddRange(a);
list.AddRange(b);

我必须做如下:

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

foreach(tblTestB item in b)
    list.Add(item)

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

有帮助吗?

解决方案

这在C#4中工作,由于 泛型协方差.与以前版本的C#不同,有一个从 IEnumerable<tblTestA>IEnumerable<TestInterface>.

该功能已经在V2的CLR中,但它只在C#4中公开(<url>4之前,框架类型也没有利用它)。它 只有 适用于泛型接口和委托(不是类),仅适用于引用类型(因此没有从 IEnumerable<int>IEnumerable<object> 例如。)它也只在有意义的地方工作 - IEnumerable<T> 是协变的,因为对象只从API中"出来",而 IList<T>不变性 因为您也可以使用该API添加值。

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

如果你没有使用C#4,那么Tim的使用建议 Enumerable.Cast<T> 是一个很好的-你失去了一点效率,但它会工作。

如果你想了解更多关于泛型方差的信息,Eric Lippert有一个 关于它的长系列博客文章, ,我在NDC2010上做了一个演讲,你可以在 NDC视频页面.

其他提示

你没做错什么: 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>());

AddRange正在期待接口对象列表,您的“a”和“b”varaibles被定义为派生类对象列表。显然,它似乎是合理的.NET可以在逻辑上使其跳转并将它们视为接口对象的列表,因为它们确实实现了接口,该逻辑仅在3.5上才会构建。

但是,这种能力(称为“协议”)已被添加到.NET 4.0,但直到您升级到那个时,您将被困在循环中,或者可能会尝试调用ToArray(),然后将结果转换为taskInterface [],或者可能是一个linq查询,以便案例每个项目,并创建一个新列表等。

ab 类型 IEnumerable<tblTestA>IEnumerable<tblTestB>
list.AddRange 要求参数为类型 IEnumerable<TestInterface>

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top