【问题标题】:How do I create a Windows Interface Form that allows user to pick between 3 object types?如何创建允许用户在 3 种对象类型之间进行选择的 Windows 界面表单?
【发布时间】:2011-06-21 01:45:22
【问题描述】:

这就是想法 - 基类是 Animal,派生类是 Bird 和 Dog。我有一个 ComboBox 供用户选择他们想要创建的动物。如何在表单级别合并和连接所有这些(frmAnimal.cs - 公共部分类 frmAnimal :表单)。

根据这个决定,它还会影响表单上的其他按钮,例如调用 .Move() 的按钮,这是一个重写的 Animal 方法,它将根据 Bird 或 Dog 调用正确的 Move() 方法选为对象类型。

这有意义吗?

【问题讨论】:

  • 据我所知,多态性已经为您解决了这个问题。只需实例化特定的派生类,它的Move 方法就会被自动调用,无论是否被覆盖。
  • 这个问题非常笼统和模糊,因此很难回答。可能值得发布您迄今为止的努力以及您正在努力解决的特定领域。
  • 对,Cody,我主要想弄清楚如何通过按钮和组合框将多态性与用户交互结合起来。

标签: c# oop class object polymorphism


【解决方案1】:

您想创建并显示一个与选择表单分开的新表单吗?如果是这样,您可以将表单类设为通用,仅限于 Animal 类型的对象:

public abstract partial class AnimalFormBase<T>:Form where T:Animal {...}

然后您可以从该表单派生以创建特定于动物的表单:

public partial class AnimalForm:AnimalFormBase<Animal> {...}
public partial class BirdForm:AnimalFormBase<Bird> {...}
public partial class DogForm:AnimalFormBase<Dog> {...}

如果你想要相同的表单但不同的控件,我会让上面的类派生自 UserControl。然后,当用户更改单选按钮时,您可以删除旧动物类型的控件并将其替换为新动物类型的控件。无论哪种方式,通用祖先 AnimalFormBase 都可以保存与任何 Animal 相关的功能。从技术上讲,它可以包含控件,但我发现设计器呈现的类中的自定义继承可能会变得混乱。然后,这三种衍生形式可以使用基本功能,添加它们自己的功能,并布置每个将呈现给用户的控件。

【讨论】:

  • 我正在考虑一些更基本的表单。表格将始终相同。因此,如果单击“移动”按钮,它会使用 Bird、Dog 或 Animal 的 Move 方法,具体取决于在 ComboBox 中选择了哪个对象。
  • 好吧,既然这三个都是动物,你可以有一个动物类型的属性,当单选按钮更改时,它会被重新实例化(或从该类型的现有对象的某些缓存中提取)到正确的类型,然后移动按钮处理程序将调用属性的 Move() 方法。那么那个按钮就不会关心属性的真实类型是什么;它知道它有一个 Move 方法(必须从 Animal 中获得)。
【解决方案2】:

我的例子是在 vb.net 中(我正在学习 C#,但还没有“那里” - 差异不是那么大以至于这没有意义,虽然......),但要领是失败的普遍的。您有一个基类 Animal,以及一些从动物派生的类。在您的基类上定义 .Move 方法。然后创建派生类,继承基类的方法和公共接口。定义 AnimalType 属性以区分动物的类型。对于这个非常简单的示例,我使用了 Enum。实际上,这可能是一个 Enum,也可能是一个数据库 PK 或其他唯一标识符。请注意,在实践中,我可能不会让 superType Animal 成为与派生类相同的枚举的成员。例如,在数据库中,我可能会将派生对象设为与“父”动物记录相关的“子”记录):

Public Enum AnimalTypes
    Animal = 1
    Pig = 2
    Human = 3
End Enum

Public Class AnimalBase

    Public Overridable ReadOnly Property AnimalType() As AnimalTypes
        Get
            Return AnimalTypes.Animal
        End Get
    End Property

    Public Sub Move(ByVal X As Integer, ByVal Y As Integer)
        ' . . . You movement code
    End Sub
End Class

现在你的派生类:

Public Class Pig
    Inherits AnimalBase

    Public Overrides ReadOnly Property AnimalType() As AnimalTypes
        Get
            Return AnimalTypes.Pig
        End Get
    End Property

    'A property spcific to the pig class:
    Public ReadOnly Property PigOnEquality() As String
        Get
            Return "Some pigs are more equal!"
        End Get
    End Property
End Class

Public Class Human
    Inherits AnimalBase

    Public Overrides ReadOnly Property AnimalType() As AnimalTypes
        Get
            Return AnimalTypes.Human
        End Get
    End Property

    'A property specific to the Human class:
    Public ReadOnly Property Shotgun() As String
        Get
            Return "Boom!"
        End Get
    End Property
End Class

现在,一个 AnimalFactory 类,它创建了 animal 的实例和派生自类型 animal 的类,如(再一次......类型 animal):

Public Class AnimalFactory

    Public Shared Function NewAnimal(ByVal AnimalType As AnimalTypes) As AnimalBase
        Select Case AnimalType
            Case AnimalTypes.Animal
                Return New AnimalBase
            Case AnimalTypes.Pig
                Return New Pig
            Case AnimalTypes.Human
                Return New Human
            Case Else
                Return New AnimalBase
        End Select
    End Function

End Class

这里的诀窍是,由 AnimalFacorty 返回的派生类是动物类型,但实现了它们真实类型的所有属性,如果需要,可以将其强制转换为它们的真实类型。现在,你的表格。如果您只访问在基类上定义的常用方法,您的表单也不必关心返回的动物类型。如果您需要访问特定于派生类的方法,则需要执行强制转换操作(在 C# 中应该与在 VB.net 中相同(或非常相似)。

我以这种形式抛出了一些非常愚蠢的例子。也有可能避免 Select Case 的方法(我相信你会知道作为 Switch 语句),但我不知道你在用你的代码做什么,所以这只是一个 acedmic excercise 。 . .

 Public Class AnimalFarm ' My hilarious name for the FORM

     'Member variable for the currently selected instance of AnimalBase
     Private SelectedAnimal As AnimalBase

     Private Sub AnimalFarm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

         'Using the enum to populate the comboBox:
         With Me.ComboBox1.Items
             .Add(AnimalTypes.Animal)
             .Add(AnimalTypes.Pig)
             .Add(AnimalTypes.Human)
         End With

     End Sub

     Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
         Dim AnimalType As AnimalTypes = Me.ComboBox1.SelectedItem
         Me.OnNewAnimalSelected(AnimalType)
     End Sub

     Private Sub OnNewAnimalSelected(ByVal AnimalType As AnimalTypes)
         SelectedAnimal = AnimalFactory.NewAnimal(AnimalType)

         'The form doesn't case what type of animal is being instantiated, so long
         'as the methods required are defined on the base class:
         MsgBox(SelectedAnimal.AnimalType.ToString)

         'Move the animal a bit, just for kicks:
         SelectedAnimal.Move(NewX, NewY)

         '  . . . But if you NEED the specific TYPE of animal:

         Select Case SelectedAnimal.AnimalType
             Case AnimalTypes.Human
                 Dim NewHuman As Human = CType(SelectedAnimal, Human)
                 MsgBox(NewHuman.Shotgun)

             Case AnimalTypes.Pig
                 Dim Piggy As Pig = CType(SelectedAnimal, Pig)
                 MsgBox(Piggy.PigOnEquality)
             Case Else
                 MsgBox("This Animal has nothing to say . . .")

         End Select
     End Sub

     Private Sub OnMoveAnimal(ByVal X As Integer, ByVal Y As Integer)
         SelectedAnimal.Move(X, Y)
     End Sub

 End Class

【讨论】:

  • 感谢您的精彩帖子!这不是我想要做的……但非常接近。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-07
  • 1970-01-01
  • 2020-01-19
相关资源
最近更新 更多