C#接口实现和泛型集合问题

时间:2009-08-18 22:21:51

标签: c#

假设我有以下代码:

public class CBase: AbstractC,IRenderable
{
 //code here
}

public class CBaseGroup
{
 private List<IRenderable> CCollection;

 public CBaseGroup(List<IRenderable> c)
 {
   CCollection=c;
 }
}

public class CGroup:CBaseGroup
{
 public CGroup(List<CBase> c):base(c) 
 //here fails because cannot convert List<CBase> to List<IRenderable>
 {
 }

}

为什么不编译?

请随意提出一个合适的标题。

来自Matthew Scharley的回答我发现代码应该是这样的:

  public class CGroup:CBaseGroup
    {
     public CGroup(List<CBase> c):base(c.Cast<IRenderable>().ToList()) 
      // cast to list since I'm not using IEnumerable
     {
     }

    }

这至少满足编译器。

4 个答案:

答案 0 :(得分:4)

要获得您想要的效果,您需要执行类似

的操作
public class CBaseGroup<T> where T : IRenderable
{
 private List<T> CCollection;

 public CBaseGroup(List<T> c)
 {
   CCollection=c;
 }
}
public class CGroup:CBaseGroup<CBase>
{
 public CGroup(List<CBase> c):base(c) 
 {
 }
}

将特定类型的IRenderable注入基类。

答案 1 :(得分:2)

C#3.5不支持逆变和协方差。我相信我听说C#4.0会(如果我错了,有人会纠正我。)

有关此问题的更广泛讨论,have a look at this other question

答案 2 :(得分:0)

那么,在第1行,您需要在任何接口

之前包含父类
public class CBase: AbstractC, IRenderable

答案 3 :(得分:0)

这是一个协方差问题,因为C#3.5不支持这种泛型类型转换。对C#4.0中的泛型共同和反对方差将有更多的支持。

以下类型的转化工作正如我们所期望的那样,已经多次完成

IRenderable renderable = cbaseObject as IRenderable;

更具体的类型cbaseObject正在类层次结构中转换为更通用的类型IRenderable。但是,以下类似于您的情况

List<CBase> listOfCBaseObjects = new List<CBase>();
IEnumerable<IRenderable> renderables = listOfCBaseObject as IEnumerable<IRenderable>;

将无效,因为当前的C#版本不支持它。

但是,自C#1.0以来,支持包含引用类型的数组的协方差。见Eric Lippert's blog port。因此,如果您执行以下操作,转换将起作用:

CBase [] cbaseObjects = new CBase[] { new CBase(),new CBase()};
IRenderable [] renderables = cbaseObjects as IRenderables[];

或者,如果需要,可以更改CBase和CBaseGroup构造函数以获取数组而不是列表。这样你就可以做到以下几点:

//constructor
public CBaseGroup(IRenderable[] c)

//constructor
public CGroup(CBase[] c):base(c as IRenderable[]) 

这应该有用。