C# - 有什么方法可以投射通用集合吗?

Rud*_*dey 6 .net c# generics casting c#-4.0

我一直忙于C#4.0泛型,现在我基本上想做这样的事情:

public abstract class GenericTree<T> : Tree
    where T : Fruit
{
    public Tree(IFruitCollection<T> fruits)
        : base(fruits) { }
}
Run Code Online (Sandbox Code Playgroud)

基本Tree类如下所示:

public abstract class Tree
{
    private IFruitCollection<Fruit> fruits;

    public IFruitCollection<Fruit> GetFruits
    {
        get { return fruits; }
    }

    public Tree(IFruitCollection<Fruit> fruits)
    {
        this.fruits = fruits;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的第一个问题.GenericTree的构造函数无法将泛型集合强制转换为水果集合.我也有GenericTree的实现:

public class AppleTree : GenericTree<Apple>
{
    public AppleTree()
        : base(new FruitCollection<Apple>) { }
}
Run Code Online (Sandbox Code Playgroud)

这是我的第二个问题.当我使用myAppleTree.GetFruits.Add(...)向AppleTree实例添加水果时,我不仅限于苹果.我被允许添加各种水果.我不想要这个.

我试图通过将其添加到GenericTree来解决该问题:

new public IFruitCollection<T> GetFruits
{
    get { return base.GetFruits as IFruitCollection<T>; }
}
Run Code Online (Sandbox Code Playgroud)

但这也是不可能的.它总是以null返回null.当我的第一个问题得到解决时,这可能会得到解决.

IFruitCollection接口如下所示:

public interface IFruitCollection<T> : ICollection<T>
    where T : Fruit { ... }
Run Code Online (Sandbox Code Playgroud)

FruitCollection类是Collection类的简单实现.哦,当然,Apple类扩展了Fruit类.

解决方案是使IFruitCollection接口兼容协方差和逆变.但是我该如何实现这一目标呢?"in"或"out"参数关键字是不可能的,因为ICollection接口不允许它.

非常感谢你的帮助!

Rud*_*dey 1

我想我在尝试 phoog 的解决方法时找到了解决方案。谢谢,噗!

起初我没有给GenericTree他自己的FruitCollection。Mosty 因为基类经常循环访问他自己的集合,例如更新水果。这导致水果不更新,因为它们被添加到 GenericTree 的集合中,而不是添加到基本集合中。

但最终我意识到,铸造这些系列也永远不会成功。

现在,我创建了另一个 FruitCollection 类,它自动向基本 FruitCollection 添加和删除组件,反之亦然。这个解决方案对我来说非常有用!

public FruitCollection<T, U> : FruitCollection<T>
    where T : U
    where U : Fruit
{
    private FruitCollection<U> baseCollection;

    public FruitCollection(FruitCollection<U> baseCollection)
        : base()
    {
        this.baseCollection = baseCollection;

        // here I added code that throws events whenever the collection is changed
        // I used those events to add/remove fruit to the base collection, and vice versa
        // see the link below.
        ...
    }

    ...
}

public class GenericTree<T>: Tree
    where T : Fruit
{
    private FruitCollection<T> fruits;

    // use the new keyword to hide the base collection
    new public FruiCollection<T> Fruits
    {
        get { return fruits; }
    }

    public GenericTree()
        : base()
    {
        // after hiding the base collection, use base.Fruits to get it
        fruits = new FruitCollection<T, Fruit>(base.Fruits);
    }
}
Run Code Online (Sandbox Code Playgroud)

这对我有帮助:如何处理添加到列表事件?