成员字段中的多态,当字段是对象的集合时,这些对象也是继承树的一部分

时间:2013-09-26 15:11:29

标签: c# oop inheritance polymorphism

我无法明确表达问题所以我将从一个例子开始:

public class BirdCollector
{
    protected Dictionary<string, Bird> nameToBird_;

    public BirdCollector(Dictionary<string, Bird> nameToBird)
    {
        nameToBird_ = nameToBird;
    }
}

public class ExoticBirdCollector
{
    public ExoticBirdCollector(Dictionary<string, Bird> nameToBird)
    : base(nameToBird)
    { }

    public ExoticBird GetExoticBird(string name)
    {
        Bird bird;
        if(nameToBird_.TryGetValue(name, out bird))
        {
            return (ExoticBird)bird;
        }
        else
        {
            // handle error
            return null;
        }
    }
}

我传入ExoticBirdCollector的词典包含所有ExoticBird,其中Bird延伸,但我不得不每次都在GetExoticBird()重播它们。

是否可以在构造函数中投射一次,这样每次我从nameToBird_获得一只鸟时它都是ExoticBird?编译器没有任何方式知道我在地图中传递了所有ExoticBirds,所以有没有办法强制执行此操作而不是声明单独的字典,例如Dictionary<string, ExoticBird> nameToExoticBird_

我现在正在考虑做的事情(这似乎不正确)是将BirdCollector中的nameToBird_设为私有而不是受保护,并将其隐藏在ExoticBirdCollector字符串和ExoticBird的字典中。 / p>

我原来的问题得到了解答,但我有一个相关的跟进。如果我要求Dictionary<string, ExoticBird>被传递到一个在构造函数中接受Dictionary<string, Bird>的新类,我怎么能实现呢?我怀疑无法进行向下投射,因为对象在容器内。我可以创建一个新的Dictionary<string, Bird>并循环遍历Dictionary<string, ExoticBird>来填充它然后传递它,但这看起来像是一个黑客。

2 个答案:

答案 0 :(得分:4)

使您的基类具有通用性并移动GetBird方法

public class BirdCollector<T> where T : Bird
{
    readonly Dictionary<string, T> nameToBird_;

    public BirdCollector(Dictionary<string, T> nameToBird)
    {
        nameToBird_ = nameToBird;
    }

    public T GetBird(string name)
    {
        T bird;

        if (nameToBird_.TryGetValue(name, out bird))
        {
            return bird;
        }

        // handle error
        return null;
    }
}

然后你可以像这样声明它的派生类

public class ExoticBirdCollector : BirdCollector<ExoticBird>
{
    public ExoticBirdCollector(Dictionary<string, ExoticBird> nameToBird)
        : base(nameToBird)
    {
    }
}

答案 1 :(得分:1)

您可以使用泛型和类型约束:

public class Bird
{  }

public class ExoticBird : Bird
{  }

public class BirdCollector<T> where T : Bird
{
    protected Dictionary<string, T> nameToBird_;

    public BirdCollector(Dictionary<string, T> nameToBird)
    {
        nameToBird_ = nameToBird;
    }
}

public class ExoticBirdCollector : BirdCollector<ExoticBird>
{
    public ExoticBirdCollector(Dictionary<string, ExoticBird> nameToBird)
        : base(nameToBird)
    { }

    public ExoticBird GetExoticBird(string name)
    {
        ExoticBird bird;
        if (nameToBird_.TryGetValue(name, out bird))
        {
            return bird;
        }
        else
        {
            // handle error
            return null;
        }
    }
}