【问题标题】:VB.NET Subclass of class containing list collection of subclassed itemsVB.NET 类的子类,包含子类项的列表集合
【发布时间】:2016-10-26 14:42:58
【问题描述】:

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

现在我想创建一个 Apple 类,它是 Fruit 的子类,我想要一个名为 AppleCart 的类,它是 FruitStand 的子类。 AppleCart 中通用 List 的内容将永远只包含 Apple 类的实例。我想要的是能够让 AppleCart 的消费者不必将 Contents 属性返回的元素从 Fruit 转换为 Apple。

我希望这是一件简单的事情,我只是精神障碍。

【问题讨论】:

  • 如果 AppleCart 只能包含 Apples,为什么还要强制转换它?
  • 与其继承自 FruitStand 的 AppleCart,或许一个接口(例如 IFruitVendor(of T))可以满足您的需求。
  • 因为超类 (FruitStand) 返回一个水果列表,而不是一个苹果列表。因此,消费者必须将从枚举器返回的 Fruit 转换为 Apple 以访问特定于 Apple 的属性。 Apple Cart 仅包含 Apple,因为它确保仅将 Apple 添加到列表中。
  • 我想到了类似 IFruitVendor 的东西,但我希望 FruitStand 的逻辑成为类的一部分,并且不需要在两个类中复制。问题是 AppleCart 仍然是一个 FruitStand,只是增加了一些功能 - 而不是不同的功能。
  • AppleCart 只有在没有覆盖/重载返回项目的方法时才会返回 Fruit。它们显然是通过 AppleCart 方法进入水果箱的,如果它们以相同的方式出来,它们就是苹果

标签: vb.net list subclass generic-list


【解决方案1】:

你可以使用泛型。

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

【讨论】:

  • 我知道我错过了一些非常简单的东西。谢谢!
【解决方案2】:

您可以对FruitStand 类使用通用约束,这会强制派生类在其声明中指定派生自Fruit 的类

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

【讨论】:

    【解决方案3】:

    我看到了 3 个选项:您可以像这样使您的 FruitStand 通用:

    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
    

    或者你切断 FruitStand 和 AppleCart 之间的关系,而是从同一个新提取的基类中派生它们(我认为这是最好的选择):

    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
    

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

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

    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
    

    【讨论】:

    • 这三种方法都有优点。就我的目的而言,最简单的方法(使 FruitStand 通用)就足够了,如 the_lotus 答案中所述。
    猜你喜欢
    • 1970-01-01
    • 2013-04-20
    • 1970-01-01
    • 2020-03-23
    • 2011-11-21
    • 1970-01-01
    • 1970-01-01
    • 2013-07-03
    • 1970-01-01
    相关资源
    最近更新 更多