Visual Basic.NET 現今是一個完整的物件導向(Object Orient)語言,也就是完整支援封裝、繼承、多型等等程式撰寫的方式,並提供建構/解構子。所以它增加了以往 Visual Basic 在這一方面所缺乏的功能,如繼承。
Visual Basic.NET 增加的繼承讓你可以其他的 Class 為基礎來建立新的 Class,衍生的(Derived) Class 可以繼承(inherit)和延伸原始 Class 的屬性和方法。雖然衍生的 Class 只能繼承自單一的基礎(base) Class,但它可以實做(implement)無限數目的介面(interface)。衍生的 Class 也可以撰寫新的方法 override 繼承下來的方法,所有 Visual Basic.NET 建立的 Class 預設都是可以被繼承的。
繼承和介面讓你可以實做多型(polymorphism),讓不同的 class 可以重新定義相同名稱的屬性和方法。多型是物件導向(object-orient)程式設計的基礎,因為它讓你可以呼叫相同名稱的方法,而不管在使用的當下是哪一種型態的物件。例如給一個 NormalPayroll 的基礎 class,多型讓程式設計師可以定義多個衍生 Class 不同的 PayEmployee 方法。其他的屬性和方法可以相同的方式使用衍生物件的 PayEmployee 方法,而不管是用到哪一個衍生的物件。
Visual Basic.NET 提供下列的語句來定義和支援繼承
Inherits 語句 -- 定義當下 Class 要繼承的 Class(也稱為基礎 class)。通常可以透過屬性視窗(properties window)來設定。
NotInheritable 定義子 -- 防止使用者將該 Class 當作基礎 class 來使用
MustInherit 定義子 -- 定義該 class 不能用來建立 instance,唯一使用它的方式是繼承它。
衍生的 class 可以新的實做方式 override 一些繼承來的方法。Visual Basic.NET 使用下列的定義子來控制方法和屬性的 overriding
Overridable -- 讓屬性和方法在繼承的 Class 可以 override
Overrides -- 定義要 override 哪一個基礎的屬性或方法
NotOverridable(預設) -- 防止屬性或方法被繼承的 class override
MustOverride -- 要求繼承的 class 一定要 override 該屬性或方法
程式碼範例如下
Imports System
Namespace MyNamespace
Class Payroll Overridable Function PayEmployee(ByVal HoursWorked As Single, ByVal PayRate As Single) PayEmployee = HoursWorked * PayRate End Function
End Class
Class BonusPayroll Inherits Payroll Overrides Function PayEmployee(ByVal HoursWorked As Single, ByVal PayRate As Single) PayEmployee = (HoursWorked * PayRate) * 1.45 ' 45% 紅利 End Function
End Class
Module MyModule Sub Main() Dim BonusPayrollItem As Bonuspayroll = New Bonuspayroll Dim PayrollItem As Payroll = New Payroll Dim PayRate As Single = 14.75 Dim HoursWorked As Single = 40
Console.WriteLine("Normal pay is: " & Pay(PayrollItem, HoursWorked, PayRate)) Console.WriteLine("Pay with bonus is: " & Pay(BonusPayrollItem, HoursWorked, PayRate))
End Sub
Function Pay(ByVal PayObject As Payroll, ByVal HoursWorked As Single, ByVal PayRate As Single) Pay = PayObject.PayEmployee(HoursWorked, PayRate) * 0.75 ' withold tax End Function End Module
End Namespace
Protected Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Dim t As New Thread(AddressOf AddVal) t.Start()
End Sub
Sub AddVal() SyncLock iary Dim i As Integer For i = 1 To 1000000 ival += 1 Next textbox1.text = CStr(ival) end synclock
End Sub
建構子(Constructor)和解構子(Destructor)
建構子是用來控制 Class 在建立一個新的 Instance 時所需要做的初始化程序。同樣地,解構子是當 Class 的 Instance 結束時(可能是設定變數為 Nothing)所需要做的程序,如釋放系統資源等等。 在原有的 VB 中,可以利用 Class_Initialize() 和 Class_Terminate() 事件程序(Event Procedure)來初始化或在 Instance 結束時執行。
在 Visual Basic.NET 中改以 Sub New() 和 Sub Destruct() 程序來做建構子與解構子的動作。
Sub New() 方法只會在 Class 建立時執行一次,且除了以同一 Class 其他的建構子或是衍生 Class 的建構子的第一行程式碼呼叫之外,不可以在任何其他地方呼叫使用。且 Sub New() 方法之內的程式碼在執行時,沒有任何該 Class 內的成員已經被建立出來。 .NET 執行環境會在清掉物件時自動呼叫它的 Sub Destruct() 方法,這一個副函數也不可以被呼叫使用。
.NET 執行環境在系統決定該物件不需要存在時﹔會自動清掉該物件。與 Class_Terminate 和 Sub New() 不同的是,你無法確切地知道 .NET 執行環境會何時呼叫 Sub Destruct(),只能確定的是對該物件最後的一個參照(reference)被釋放後,系統會自動呼叫 Sub Destruct()。
■ 使用 Sub New() 來建立參數化的建構子 --
要建立一個 class 的建構子可以在 class 定義範圍內的任何地方撰寫 Sub New() 副函數。建構子的第一行程式碼必須是呼叫基礎 Class 的建構子或是同一 Class 內其他的建構子,這保證被繼承的物件會在衍生的物件之前初始化完成。甚至是當你在建立你自己的基礎 class 時,也通常會呼叫 MyBase.New 來初始化更基礎的物件,因為所有的 Class 最終都是繼承自 Object Class。
在呼叫完父物件的建構子後,在 Sub New() 副函數內加上初始化該物件所需要的動作。Sub New() 副函數可以接受參數,如下列的程式碼範例。
■ 使用 Sub Destruct() 當解構子 --
要建立 class 的解構子,可以在 class 的定義範圍內任何地方加上 Sub Destruct() 副函數。你可以在該副函數內加上釋放物件,關閉檔案等等工作。
程式碼範例如下
Imports System
Namespace MyNamespace
Module MyModule Class Truck Private iWheels As Integer Sub New(iInitialWheels As Integer) MyBase.New '呼叫基礎 Class 的建構子 iWheels=iInitialWheels End Sub Sub Destruct() '執行一些需要的動作 End Sub Property Wheels As Integer Get Wheels=iWheels End Get Set iWheels = Value End Set End Property End Class
Sub Main() Dim t as Truck = New Truck(18) Console.WriteLine("這是一部 {0} 輪大卡車",t.Wheels) Console.Write("請輸入您想要改裝的輪數: ") t.Wheels = CInt(Console.ReadLine()) Console.WriteLine("你已經把它改裝成 " & t.Wheels & " 輪大卡車") End Sub
End Module
End Namespace
執行結果如下
Delegate
Delegates 的行為像一個 type-safe,物件導向式函數指標(object-oriented function pointer)。利用 delegate 傳遞用 VB 的 addressof 運算子取得 class 副函數的指標給其他的 VB class 副函數。通常會利用 Delegate 來做事件處理函數,也就是當事件發生時要自動執行的函數。
每一個 delegate class 定義一個建構子,使用時會傳入一個物件方法的指標當作是參數。參數的格式如下
AddressOf [.]<方法名稱>
在編譯時期, 必須是一個 class 或是一個介面(interface),並且有著一個符合 delegate class 所宣告的方法格式的方法。
這個方法可以是共享的(class)方法或是 instance 方法。 要觸發 delegate class 的 instance 內的方法必須要呼叫內建的 Invoke 方法,整個程式碼範例如下
Imports System
Namespace TestDelegate Public Delegate Sub EventHandler(ByVal strText As String)
Class EventTake Sub GetEvent(ByVal strIn As String) console.WriteLine("Delegate 事件 " & strIn) End Sub
End Class
Class EventRaise Sub UseInvoke() Dim c As New EventTake() Dim DelSub As EventHandler delsub = New EventHandler(AddressOf c.getevent) delsub.Invoke("一些狀況") End Sub
End Class
Module Module1
Shared Sub Main() Dim c2 As New EventRaise() c2.UseInvoke() End Sub