开发者

Passing Base Object Type When Using Inherited One

开发者 https://www.devze.com 2023-01-19 02:28 出处:网络
I have a project that has mainly two objects, both inheriting from a base. Like this: Public Class Vehicle

I have a project that has mainly two objects, both inheriting from a base. Like this:

Public Class Vehicle
    Property Model As String
    Property Make As String
End Class

Public Class Truck
    Inherits Vehicle
    Property IsFlatbed As Boolean
End Class

Public Class Car
    Inherits Vehicle
    Property LeatherSeats As Boolean
End Class

Simple enough, eh? Because I don't know if a user will choose car or truck, what I would like to do is just pass around Vehicle.

So, something like this:

Public v As 开发者_C百科Vehicle
Sub WhichVehicle()
    Select Case cmbVehicle.SelectedItem
        Case Truck
            v = New Truck
        Case Car
            v = New Car
    End Select
    SetFlat (v)
End Sub

This all works, but now I just want to pass v around and use it's properties. Like:

Sub SetFlat (myVehicle As Vehicle)
    myVehicle.IsFlatbed = True
End Sub

The above function doesn't work because myVehicle is a Vehicle, not a Truck.

Is there a way I can pass around a Vehicle type and have the IDE know which type to use? Or am I completely missing a better way to do this?


Basically when you call SetFlat you know your vehicle has a property named IsFlatbed, right?

Then you should declare an interface Flattable which includes this property. The class Truck would implement that interface, and the SetFlat sub would have a Flattable object as a parameter instead of a vehicle.

Edit:

What about this:

Public Interface IFlattable
    Property IsFlatbed() As Boolean
End Interface

Public Class Truck
    Inherits Vehicle
    Implements IFlattable

    Private _isFlatBed as Boolean
    Public Property IsFlatbed() as Boolean Implements IFlattable.IsFlatbed
        Get
            Return _isFlatbed
        End Get
        Set(ByVal value as Boolean)
            _isFlatbed = value
        End Set
End Class


Public v As Vehicle
Sub WhichVehicle()
    Select Case cmbVehicle.SelectedItem
        Case Truck
            v = New Truck
            SetFlat (DirectCast(v, IFlattable))
        Case Car
            v = New Car
    End Select
End Sub

Sub SetFlat (myVehicle As Flattable)
    myVehicle.IsFlatbed = True
End Sub


This is one way you could achieve this:

Imports System.Reflection
Module main_
    Sub Main()
        Dim t As New Truck
        Dim c As New Car
        Dim v As Vehicle
        v = t
        SetFlat(v)
        v = c
        SetFlat(v)
    End Sub
    Sub SetFlat(ByVal v As Vehicle)

        Dim vehicletype As Type
        Dim members() As PropertyInfo

        vehicletype = v.GetType
        members = vehicletype.GetProperties

        Console.Write("v is a " & vehicletype.ToString)
        For Each m As PropertyInfo In members
            If m.Name = "IsFlatbed" Then
                m.SetValue(v, True, Nothing)
                Console.WriteLine(" and now it's a flatbed")
                Exit Sub
            End If
        Next
        Console.WriteLine(" so flatbed doesn't apply")
    End Sub
End Module

Output:

v is a Vehicles.Truck and now it's a flatbed
v is a Vehicles.Car so flatbed doesn't apply


I found two approaches which may help you.

The more elegant one is to force your base to subclass by usage of a generic method without type inference. It could look something like (I'm not a VB.Net programmer so there may be some errors):

Sub SetFlat(of T) (myVehicle As T)
    T.IsFlatbed = True
End Sub
// later you can just call
SetFlat(Of Truct)(myVehicle)  

Of course this implies that you need to know the exact type of myVehicle object before calling SetFlat function. Also SetFlat can only be called with classes which do have the IsFlatbed property. Some more details about generics in VB.Net:
http://www.15seconds.com/issue/040526.htm
http://msdn.microsoft.com/en-us/library/w256ka79%28VS.80%29.aspx
Generic Functions in VB.NET

A second (dirty) solution is to use .Net reflection to detect if the myVehicle object contains the IsFlatbed property. You may find more details on:
http://msdn.microsoft.com/en-us/magazine/cc163750.aspx
http://visualbasic.about.com/od/usingvbnet/a/proginfo.htm
http://www.eggheadcafe.com/community/aspnet/14/14989/reflection.aspx


I decided to fire up Visual Studio and do some testing because my comments to the other answers probably won't make much sense. Assuming that you have the following classes:

Public Class Vehicle
   Public Property Model As String
   Public Property Make As String
End Class

Public Class Truck : Inherits Vehicle
   Public Property IsFlatbed As Boolean
End Class

Public Class Car : Inherits Vehicle
   Public Property LeatherSeats As Boolean
End Class

You could also have the following methods in another class:

Private Sub WhichVehicle()
    Select Case cmbVehicle.SelectedItem
        Case Truck
            v = New Truck
        Case Car
            v = New Car
    End Select

    SetFlat(v)
End Sub

Private Sub SetFlat(ByVal myVehicle As Vehicle)
   If TypeOf myVehicle Is Car Then
      Debug.WriteLine("This is a car")

      Dim c As Car = DirectCast(myVehicle, Car)
      c.LeatherSeats = False
   ElseIf TypeOf myVehicle is Truck Then
      Debug.WriteLine("This is a truck")

      Dim t As Truck = DirectCast(myVehicle, Truck)
      t.IsFlatbed = True
   End If
End Sub

So, this allows you to pass around a vehicle object as you were wanting, because you won't know until run-time what specific type of vehicle that you are dealing with (either a Car or a Truck). The SetFlat method can determine during run-time what specific sub-class of vehicle that it was passed, and act accordingly. You just have to make sure that you cast the generic vehicle object (v) to a new object of the more specific sub-class after you've determined which type of sub-class that it is (either c for Car or t for Truck), otherwise the code will not compile because you would be trying to call a method that does not exist on the generic vehicle type, but only on the specific sub-types of vehicles.

The biggest downside that I see to this approach is that it may start to get tedious if you have a lot of code. This is because each method that you want to call will have to check to see which type of specific vehicle object that it was passed, and run a different set of routines depending on that specific type.


I think you should give some more details about what you try to acomplish... Anyways, in VB you have an operator to determine if an object is of a type, that is the typeof operator. You could test if v is a Truck and use a cast operator (DirectCast, CType) to cast v to a Truck, like

Dim v as Vehicle
'...
If typeof v is Truck then SetFlat(DirectCast(v, Truck))

EDIT: SetFlat should take a Truck as parameter, only that makes sense.

0

精彩评论

暂无评论...
验证码 换一张
取 消