在基类构造函数中使用抽象类作为参数,以在派生类中具有更多特定类型

时间:2019-05-04 17:16:05

标签: c# oop inheritance

来自数据科学领域,我正尝试学习使用c#进行软件开发的方法。

我正在尝试建立一个基础类(例如Aliments),从中可以衍生出其他一些甚至更具体的自定义列表类(例如Fruits和Vegs)。在侧面,我有一些分别来自Aliment的Fruit和Veg类。最后,我希望Fruits / Vegs实例具有Veg / Fruit专有性列表(以及一些针对Fruits和Vegs类的专有性和方法)。但我希望此清单专有性可以在Aliments基类中实现,并提供一些管理它的方法(例如RemoveRipe(),SortBySize()...)

我试图在Aliments类中放置一个List适当性,然后使用List 或List 使派生类(Fuits / Vegs)调用基本构造函数。

我尝试过这样的事情:

public abstract class Aliment
{
    public int Ripeness;
}

public class Fruit : Aliment
{
    // be a fruit
}

public abstract class Aliments
{
    public Aliments(List<Aliment> alimentList)
    {
        AlimentList = alimentList;
    }

    public List<Aliment> AlimentList { get; private set; }

    public void RemoveRipe()
    {
        //...
    }
}

public class Fruits : Aliments
{
    public Fruits(List<Fruit> fruitList)
        : base(fruitList)
    {

    }
}

主要问题是水果清单无法转换为食品清单。此外,操作的重点是每个“水果”实例都有一个“实际水果”列表(以便我可以访问“水果”的特定方法)。有什么办法可以做到吗?我的方法好吗? 预先感谢

P.S。抱歉,如果重复的话,我真的没怎么提出问题以进行搜索

1 个答案:

答案 0 :(得分:2)

当我们说不能将List<Fruit>转换为List<Aliment>时,很大程度上取决于我们所说的“转换”。

如果您有一个List<Fruit>并且想要一个List<Ailment>,则可以通过创建一个新列表来实现。例如,如果fruitListList<Fruit>

var alimentList = new List<Aliment>(fruitList.Cast<Aliment>())

由于每个Fruit是一个Aliment,因此您可以将每个Aliment转换为List<Aliment>并使用它们来填充新的{{1} }。

如果这样做,您的Fruits构造函数将编译:

public class Fruits : Aliments
{
    public Fruits(List<Fruit> fruitList)
        : base(new List<Aliment>(fruitList.Cast<Aliment>()))
    { }
}

我们不能做的是将List<Fruit>转换为List<Aliment>

为什么?因为如果可以的话,我们可以这样做:

var alimentList = (List<Aliment>)fruitList;
alimentList.Add(new Vegetable());

这不会创建新列表-它只会将列表转换为其他类型。但是,如果我们可以将List<Fruit>转换为List<Aliment>,则可以将任何Aliment添加到列表中,包括Vegetable。这样我们的Vegetable中将有一个List<Fruit>

这在我们前面并不总是很明显,但是编译器会立即发现并阻止它。

由于这个问题,如果使用上面显示的代码修复构造函数中的错误,您仍然会遇到完全相同的问题。 Fruits仍将具有一个List<Aliment>继承的Aliments属性,因此您仍然可以这样做:

var fruits = new Fruits(someListOfFruit);
fruits.AlimentList.Add(new Vegetable());

这不会给您带来编译器错误,但显然仍然不是您想要的行为。

像这样的通用类可能会帮助您:

public abstract class Aliments<T> where T : Aliment
{
    public Aliments(List<T> alimentList)
    {
        AlimentList = alimentList;
    }
    public List<T> AlimentList { get; private set; }
}

它允许您执行此操作。您可以定义一个继承自Aliments但指定Aliment实际类型的类。

public class Fruits : Aliments<Fruit>
{
    public Fruits(List<Fruit> alimentList) : base(alimentList)
    {
    }
}

通过为通用参数Fruit指定T,您的AlimentList属性现在定义为List<Fruit>。编译器将只允许您向其中添加Fruit