包含子类项列表集合的类的VB.NET子类

包含子类项列表集合的类的VB.NET子类,vb.net,list,subclass,generic-list,Vb.net,List,Subclass,Generic List,考虑一个名为Fruit的类和一个名为FruitStand的类,该类包含一个通用的水果列表,并公开一个属性(Contents)来获取水果列表,以便在类中迭代水果 现在我想创建一个类Apple,它是水果的一个子类,我想创建一个名为AppleCart的类,它是水果摊的一个子类。AppleCart中泛型列表的内容将只包含Apple类的入口。我想要的是能够让AppleCart的消费者不必将Contents属性返回的元素从Fruit强制转换到Apple 我希望这是一件简单的事情,我只是有一个心理障碍。您可以

考虑一个名为Fruit的类和一个名为FruitStand的类,该类包含一个通用的水果列表,并公开一个属性(Contents)来获取水果列表,以便在类中迭代水果

现在我想创建一个类Apple,它是水果的一个子类,我想创建一个名为AppleCart的类,它是水果摊的一个子类。AppleCart中泛型列表的内容将只包含Apple类的入口。我想要的是能够让AppleCart的消费者不必将Contents属性返回的元素从Fruit强制转换到Apple


我希望这是一件简单的事情,我只是有一个心理障碍。

您可以对
水果摊
类使用一个通用约束,强制派生类在其声明中指定一个派生自
水果的类

Sub Main()
    Dim ac As New AppleCart({New Apple(), New Apple()})
    For Each a In ac.Fruits
        a.Rot() ' prints "The apple is rotten!"
    Next
    Console.Read()
End Sub

Public Class Fruit
    Public Overridable Sub Rot()
        Console.WriteLine("The fruit is rotten!")
    End Sub
End Class

Public Class Apple
    Inherits Fruit
    Public Overrides Sub Rot()
        Console.WriteLine("The apple is rotten!")
    End Sub
End Class

Public Class FruitStand(Of T As Fruit)
    Private _fruits As List(Of T)
    Public ReadOnly Property Fruits As IEnumerable(Of T)
        Get
            Return _fruits
        End Get
    End Property
    Public Sub New(fruits As IEnumerable(Of T))
        _fruits = fruits.ToList()
    End Sub
End Class

Public Class AppleCart
    Inherits FruitStand(Of Apple)
    Public Sub New(fruits As IEnumerable(Of Apple))
        MyBase.New(fruits)
    End Sub
End Class

你可以使用泛型

Sub Main()

    Dim cart As New AppleCart

    cart.Fruits.Add(New Apple)

End Sub

Class FruitStand(Of T As Fruit)

    Public Property Fruits As List(Of T)

End Class

Class Fruit

End Class

Class AppleCart
    Inherits FruitStand(Of Apple)

End Class

Class Apple
    Inherits Fruit

End Class

我看到了3种选择:你要么让你的
水果摊
像这样通用:

Class FruitStand(Of TFruit As Fruit)
  Public ReadOnly Property Contents As List(Of TFruit)
End Class

NotInheritable Class AppleCart
  Inherits FruitStand(Of Apple)
End Class
或者您断开
水果站
AppleCart
之间的关系,而是从同一个新提取的基类派生它们(我认为这是最整洁的选项):

在这两种情况下,我都密封了派生的
AppleCart
,因为从它派生的任何类型都无法覆盖
TFruit
的类型。在层次结构中的该点,
内容的类型
关闭

最后,您可以使用阴影来更改派生类型中
内容的含义。问题是:您必须为基类型的
内容
属性使用协变集合(这意味着使用只读接口,如
IReadOnlyList(Of Fruit)
或数组-无论哪种方式,您都将失去添加或删除元素的能力):


如果AppleCart只能包含苹果,为什么有人要强制转换它呢?与其说AppleCart继承自水果摊,不如说一个接口(例如
IFruitVendor(of T)
)可以满足您的需要。因为超类(水果摊)返回的是水果列表,而不是苹果列表。因此,消费者必须将枚举器返回的水果扔给苹果,才能访问苹果特有的属性。Apple Cart只包含苹果,因为它确保只有苹果被添加到列表中。我想到了类似IFruitVendor的东西,但我希望水果摊的逻辑成为类的一部分,而不需要在两个类中都复制。问题是,AppleCart仍然是一个水果摊,只是添加了一些功能——没有不同的功能。AppleCart只有在没有覆盖/重载返回项目的方法时才会返回水果。它们显然是通过AppleCart方法进入水果箱的,如果它们以同样的方式出来,它们就是ApplesI知道我遗漏了一些非常简单的东西。谢谢这三种方法都有优点。就我的目的而言,最简单的方法(使水果摊通用化)已经足够了,如荷花大学的答案所述。
MustInherit Class FruitStandBase(Of TFruit As Fruit)
  Public ReadOnly Property Contents As List(Of TFruit)
End Class

NotInheritable Class FruitStand
  Inherits FruitStandBase(Of Fruit)
End Class

NotInheritable Class AppleCart
  Inherits FruitStandBase(Of Apple)
End Class
Class FruitStand

  Public ReadOnly Property Contents As IReadOnlyList(Of Fruit)

  Public Sub New()
    Me.New(New List(Of Fruit))
  End Sub

  Protected Sub New(contents As IReadOnlyList(Of Fruit))
    Me.Contents = contents
  End Sub

End Class

Class AppleCart
  Inherits FruitStand

  Public Shadows ReadOnly Property Contents As IReadOnlyList(Of Apple)
    Get
      Return CType(MyBase.Contents, IReadOnlyList(Of Apple))
    End Get
  End Property

  Public Sub New()
    MyBase.New(New List(Of Apple))
  End Sub

End Class