2010-10-08 86 views
4

我有一個項目,主要有兩個對象,都從一個基地繼承。就像這樣:使用繼承基類對象時傳遞基類對象類型

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 

足夠簡單,是嗎?因爲我不知道用戶是否會選擇汽車或卡車,我想要做的只是傳遞Vehicle

所以,這樣的事情:

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

這一切工作,但現在我只是想通過v周圍,並使用它的屬性。像:

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

上述功能不起作用,因爲myVehicleVehicle,而不是一個Truck

有沒有辦法繞過Vehicle類型並讓IDE知道使用哪種類型?或者我完全錯過了一個更好的方法來做到這一點?

回答

2

這是你能做到這一點的一種方法:

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 

輸出:

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

所有其他人都有很好的建議,但這是最符合我需求的。謝謝! – Stan 2010-10-17 19:21:10

+0

很高興爲您服務,並感謝您接受我的回答。正如你可能想象的那樣,這只是System的冰山一角。反思是關心的;如果您想更深入地探索這條大道,請隨時聯繫我。 – smirkingman 2010-10-17 21:16:19

3

基本上,當你撥打SetFlat你知道你的車輛有一個名爲IsFlatbed的屬性,對吧?

然後你應該聲明一個包含這個屬性的接口Flattable。類Truck將實現該接口,並且SetFlat子將具有Flattable對象作爲參數而不是車輛。

編輯:

這個怎麼樣:

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 
+0

我不知道這意味着什麼,接口'Flattable'事情。我想使用'v'來傳遞的原因是我還有其他的對象可以傳遞它。例如,「保修」類。我可能需要該類中的'.IsFlatbed',但只有當'v'擁有它時(否則它什麼都不等於)。如果我必須單獨通過卡車和汽車,我需要兩個不同的保修課......我想。 – Stan 2010-10-08 19:38:28

+0

對於布爾屬性(如IsFlatbed)的特殊情況,您可以始終有一個基類(Vehicle),它將所有這些屬性實現爲可重寫(虛擬)方法,但返回false。然後,您可以在派生類中重寫那些可能需要返回不同值的屬性,例如在派生類Truck中。這當然只能在這個人爲的例子中起作用,但是值得一想,它使得使用Vehicle基類非常容易。 – 2010-10-16 04:07:00

0

我覺得你應該給你嘗試什麼acomplish ... 不管怎麼說,一些細節在VB中你有一個運營商,以確定是否一個對象是一個類型,即typeof運算符。你可以測試是否v是卡車和使用轉換運算符(DirectCast,CTYPE)投v到卡車,像

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

編輯:SetFlat應採取卡車作爲參數,僅是有道理的。

+0

我已經在上面提供了大量的細節以及其他答案的評論。直接鑄造v到卡車用V時,仍然不給我車的性能。 – Stan 2010-10-11 23:28:58

+0

DirectCast(V,卡車)會給你卡車 – jaraics 2010-10-12 05:29:47

+0

的所有屬性在你的情況下,更好的解決方案可能會繼續有SetFlat接受的車輛,它的參數,但是然後執行類型轉換本身。例如,您傳入車輛,它會檢查「TypeOf V is Truck」,如果是,則將v投射到卡車(如卡車= DirectCast(v,卡車))。然後,SetFlat中的方法調用可以與t對象一起工作,就好像它是卡車一樣,因爲它是。如果「TypeOf V IsNot Truck」,你可以拋出一個異常,或者總是返回False,或者任何合適的。 – 2010-10-16 04:11:47

2

我發現了兩種方法可以幫助你。

更優雅的是通過使用泛型方法強制你的基類進行子類化,而不需要類型推斷。 它可能看起來像(我不是一個VB.Net程序員,所以可能會有一些誤差):

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

當然,這意味着你需要知道myVehicle對象的確切類型的主叫 SetFlat前功能。 SetFlat也只能用具有IsFlatbed屬性的類來調用。 在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

第二(髒)解決方案是使用。網絡反射來檢測myVehicle對象是否包含IsFlatbed屬性。您可能會發現更多細節:
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

2

我決定火了Visual Studio和做一些測試,因爲我對其他答案的評論可能不會太大的意義。假設你有以下類:

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 

你也可以在另一大類下面的方法:

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 

因此,這可以讓你通過車輛周圍的物體如你想要的,因爲直到運行時,你纔會知道你正在處理哪種特定類型的車輛(無論是汽車還是卡車)。 SetFlat方法可以在運行期間確定它通過的具體子類別,並據此採取行動。在確定了哪種類型的子類之後,您必須確保將通用車輛對象(v)投射到更具體的子類的新對象(c代表Car或t代表Truck ),否則代碼將無法編譯,因爲您將嘗試調用通用車輛類型中不存在的方法,但只能調用特定子類型的車輛。

我看到這種方法最大的缺點是,如果你有很多代碼,它可能開始變得單調乏味。這是因爲您要調用的每個方法都必須檢查它是否通過了哪種類型的特定車輛對象,並根據特定類型運行一組不同的例程。