繁体   English   中英

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

[英]Using abstract class as parameter in base class constructor to have more specific types in derived classes

来自数据科学,我正在尝试使用C#学习oop进行软件开发。

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

我试图在Aliments类中放置一个List适当性,然后使用List <Fruit>或List <Veg>使派生类(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)
    {

    }
}

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

PS对不起,如果它是重复的,我真的没有如何提出问题以便进行搜索

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

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

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

因为每种Fruit 都是一种Aliment ,所以您可以将每种Fruit浇铸为一种Aliment并使用它们填充新的List<Aliment>

如果这样做,那么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 然后我们的List<Fruit>中将有Vegetable

对于我们来说,这并不总是显而易见的,但是编译器会立即发现并阻止它。

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

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)
    {
    }
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM