我有一个定义如下的接口:
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)
有什么我做错了吗?谢谢你的帮助
由于通用协方差,这适用于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视频页面上观看.
你没有做错什么: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)