簡體   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