我有一个定义如下的接口:
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; } }
我有来自tblTestA和tblTestB的数据库记录填充的IEnumerable列表a和b
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中公开(并且框架类型在.NET 4之前也没有利用它).它仅适用于通用接口和委托(不是类),仅适用于引用类型(因此不存在从IEnumerable< int>到IEnumerable< object>的转换).它也仅适用于有意义的地方 – IEnumerable< T>因为对象仅仅来自API,而IList< T>是协变的.是不变的,因为您也可以使用该API添加值.
支持通用逆变,在另一个方向工作 – 例如,您可以从IComparer< object>转换.到IComparer< string>.
如果您没有使用C#4,那么Tim建议使用Enumerable.Cast< T>是一个很好的 – 你失去了一点效率,但它会工作.
如果你想了解更多关于泛型差异的知识,Eric Lippert有一个long series of blog posts about it,我在NDC 2010上谈了它,你可以在NDC video page上观看.