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

本文关键字:对象 字段 继承 一部分 成员 集合 多态性 | 更新日期: 2023-09-27 18:32:59

我在阐明问题时遇到了问题,所以我将从一个例子开始:

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_

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

我最初的问题得到了回答,但我有一个相关的后续问题。如果我要求将Dictionary<string, ExoticBird>传递到一个接受构造函数中Dictionary<string, Bird>的新类中,我该如何实现呢? 我怀疑无法进行向下投射,因为对象在容器内。 我可以创建一个新Dictionary<string, Bird>并循环遍历Dictionary<string, ExoticBird>以填充它,然后传递它,但这似乎是一个黑客。

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

使基类泛型并移动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)
    {
    }
}

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

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;
        }
    }
}