将未知对象转换为接口的泛型接口(从最初显式泛型类型的泛型集合类型)

时间:2015-07-30 13:49:05

标签: c# generics casting

基本上我得到了那些样本类:

public interface IHasParts<TCollectionType> : where TCollectionType : ICollection
{
  TCollectionType Parts { get; set; }
}

public class CarPart
{
  //...
}

public class Car : IHasParts<List<CarPart>>
{
  public List<CarPart> Parts { get; set; }
  //...
}

是的,我需要在这里使用ICollection的通用接口,因为实现IHasParts的类需要基于一些硬编程条件的Parts的不同列表类型。

现在我得到了Car的未知对象,我需要将其转换为仍具有Parts属性的最高父级:

Car c = new Car() {
  Parts = new List<CarPart>() {
    // ...
  }
};

object o = (object)c;

int partsCount = ((IHasParts<ICollection>)o).Parts.Count; // InvalidCastException

我该怎么做? DotNetFiddle

3 个答案:

答案 0 :(得分:4)

这是一个差异问题。

您假设,因为List<T>ICollection的子类型,因此IHasParts<List<T>>也必须是IHasParts<ICollection>的子类型。它没有。

如果您希望IHasParts<A>成为IHasParts<B>的子类型,其中AB的子类型,那么您需要IHasParts 类型参数T中的协变(使用out关键字)。

public interface IHasParts<out TCollectionType> : where TCollectionType : ICollection
{
     TCollectionType Parts { get; }
}

对于要协变的类型,T只能用于协变位置:方法返回类型,只用属性类型和只用索引器。

它不能再用于逆变位置:方法参数,属性/索引器设置器。

答案 1 :(得分:2)

如果您使用ICollection而不是List<CarPart>定义Car类,则可以使用:

public class Car : IHasParts<ICollection>
{
    public ICollection Parts { get; set; }
}

您仍然可以使用List<CarPart>

初始化您的部件

答案 2 :(得分:1)

添加一个抽象类来处理指定ICollection类型。声明你的代码是这样的:

public interface IHasParts
{
    ICollection Parts { get; }
}

public abstract class HasParts<TCollectionType, TPartType> : IHasParts where TCollectionType : ICollection
{

    public TCollectionType Parts;


    ICollection IHasParts.Parts { get { return this.Parts; } }

}

public class CarPart
{
    //...
}

public class Car : HasParts<List<CarPart>, CarPart>
{
    protected void AddParts()
    {
        this.Parts.Add(new CarPart());
    }
}

更新:

以下是您的DotNetFiddle的更新版本:https://dotnetfiddle.net/O3JZgc