程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> Visual Basic語言 >> VB綜合教程 >> 運用VB.NET的面向對象的特征

運用VB.NET的面向對象的特征

編輯:VB綜合教程
促使我們從VB6轉向VB.NET的一個最大的原因就是VB.Net對面向對象編程(OOP)這一概念的完全支持。然而,要運用這個功能,只學習一些新的關鍵字是遠遠不夠的。面對這麼多可供選擇的新的功能,你可能會感到困惑。因此,我將在本文中說明如何在你的應用程序中運用面向對象的功能。我不會深入講述每個新的功能(要進行深入講述,用整本雜志的篇幅都不夠),另外我也提供了代碼例子,在可執行的代碼中有注釋,它們有助於你對一般概念的理解。你可能對我用的一些詞不太熟悉,因此我提供了一個最常用的OOP術語表(見工具條“OOP術語表”)。
  
  你在應用程序中可能會經常用到的第一個面向對象的語言的特征是方法重載(method overloading)。VB.Net可以讓你用一個特定的名字定義多個方法或屬性,只要它們的參數定義不同;這就是說,它們的參數的數量或類型必須是不同的。例如,一個類可以定義一個GetItem方法,它帶有的參數可以是一個數字或字符串,我們根據參數類型來返回元素: Function GetItem(ByVal index As _
  Integer) As Object
  ' return an element by its index
  End Property
  
  Function GetItem(ByVal key As String) _
  As Object
  ' return an element by its key
  End Property
  
  編譯器通過查看參數的類型來調用正確的版本: res = obj.GetItem(1)   ' numeric key
  res = obj.GetItem("Joe") ' string key
  
  當你有一個可以采用任何數據類型的很普通的方法時,方法重載尤其有用——例如,一個將參數值添加到一個文本文件的Log方法。你可能想定義一個采用Object參數的單獨的版本,因為你想將任何類型的數據傳遞到這個方法: Sub Log(ByVal value As Object)
  ' TW is a TextWriter object
  tw.Write("LOG:" & value.ToString())
  End Sub
  
  然而,如果你將一個值類型的參數(一個數字、日期/時間、一個布爾值或一個結構)傳遞到一個Object參數,那麼你就暗中強加了一個封裝操作。.Net runtime必須用一個對象來封裝值——這麼做就會從托管堆(managed heap)分配內存,而且浪費了寶貴的CPU周期。
  
  一個更好的方法就是為你支持的每種數據類型定義同一個方法的重載的版本。如果你不想為每種可能的參數類型寫代碼,你可以實現一個采用Long參數的版本(它可以處理Boolean、Short、Integer和Long類型的值)、一個采用Double參數的版本(它也可以處理Single類型的值)和另外兩個分別采用DateTime值和Decimal參數的重載的版本。這四種版本可以處理最常用的值類型,而讓采用一個Object參數的重載的版本來處理引用類型(如字符串)或更特殊的對象(如Person)。將一個字符串或一個特殊的對象傳遞到采用一個Object參數的版本不會增加CPU的費用,因為它沒有強加封裝操作。
  
  構造器提供了強大的類
  在創建一個類庫時,你應該用多個重載的方法,而不要用采用可選參數的一個單獨的方法,因為有些.NET語言(C#最明顯)不能識別可選參數。記住,兩個重載的方法的不同不僅體現在它們的返回值或你用於每個參數前的ByVal/ByRef關鍵字上。(ByVal/ByRef關鍵字適用於VB.NET和其它一些.Net語言;C#可以讓你定義兩個只在ref或out關鍵字上有區別的方法。)
  
  接下來我們要探究的一個面向對象的特征就是構造器(constructor)。VB.NET構造器是一個名為Sub New的過程,當客戶端創建類的一個實例時,就會調用這個過程。如果你的代碼不包含一個明確的構造器,VB.NET編譯器就會自動添加一個缺省的構造器——一個不帶任何參數的構造器。如果沒有明確的(explicit)或隱含的(implicit)構造器,你就不能實例化類。VB.Net也可以讓你定義一個帶有參數的構造器,所以你可以讓客戶端實例化在有效狀態創建對象所必需的字段: ' a read-only fIEld can be set only
  ' from inside a constructor procedure
  Public ReadOnly Filename As String
  Sub New(ByVal filename As String)
  ' ensure filename isn't null
  If filename Is Nothing OrElse _
  Filename.Length = 0 Then
  Throw New ArgumentException("Invalid file name")
  End If
  ' assign to the read-only fIEld
  Me.FileName = filename
  End Sub
  
  帶有參數的多個構造器通常有共同的代碼——例如,驗證一個或多個參數的代碼。這時候,你就可以簡化你的類的結構,讓一個構造器調用另一個構造器: Public ReadOnly Overwrite As Boolean
  Sub New(ByVal filename As String, _
  ByVal overwrite As Boolean)
  ' a call to another constructor MUST
  ' be the first executable statement
  Me.New(filename)
  ' assign remaining fIElds
  Me.Overwrite = overwrite
  End Sub
  
  當你既需要缺省的構造器,也需要一個或多個帶有參數的構造器時,就會出現一個有趣的問題。在這種情況下,你必須明確聲明一個空的Sub New過程,因為編譯器不會自動為你創建它: Sub New()
  ' no need to add code here
  End Sub
  
  構造器的范圍對類的行為有重要的含義。一個Public類中的FrIEnd構造器使我們只可以從同一個程序集內部創建這個類,所以它同你在VB6的類中用的PublicNotCreatable設置有很多共同之處。一個私有的(private)構造器使這個類根本不能創建,如果類只是共享方法的一個容器,這種構造器就很有用。(這樣的類的例子有System.Console和System.Environment。)更確切地說,一個代碼片段可以實例化一個帶有私有構造器的類,只要那個代碼位於類內部或嵌套的類中,因為一個嵌套的類型可以訪問包含它的類型的私有的成員。創建只包含一個共享成員的一個VB.NET類的更簡單的方法就是定義一個Module。Module是規則的、不能創建的類,它的成員是靜態的。注意,.NET runtime對模塊並不很重視(C#中沒有Module):VB.Net對模塊的支持只可以簡化VB6代碼的移植,而且編譯器將一個Module中的所有成員都明確地轉換成靜態成員。
  
  注意初始化字段
  前面的講述可能意味著私有構造器只有在很少的情況下才有用,但實際並不是這樣的。例如,當你的類包含許多字段的初始化設置時,定義一個空的Private Sub New過程就很方便: Public MinSize As Integer = 10
  Public MaxSize As Integer = 1000
  ' ...(other fIElds with initializers)
  
  編譯器在每個構造器開始處都會進行隱含的賦值,保證在構造器運行時,所有的字段都包含正確的初始值。如果你有20個初始化字段和10個構造器,那麼你的類就會包含多達200個隱含的賦值,這樣就會浪費內存中和磁盤上的字節。如果你定義一個虛擬的不帶參數的私有構造器,並讓所有的公有構造器調用它,那麼編譯器就只添加20個隱含的語句到私有構造器中。通過Microsoft Intermediate Language Disassembler(ILDASM)運行產生的可執行的文件,你就可以看到在每種情況下編譯器創建的代碼。
  
  當客戶端要通過一個共享的函數(作為類的工廠方法(factory method ))來創建類的實例時,就體現了私有構造器的另一個好處。一個共享的方法可以讓你在創建類的一個新實例前運行一些代碼——例如,查看一個具有相同屬性的對象是否在你內部管理的對象池中。你不能用一個規則的構造器來實現這種功能,因為只有在一個新實例已經運行時,規則的構造器的代碼才運行(見列表1)。
  
  你在從一個類派生一個更簡單的新類時,可以看到OOP的強大。派生的類自動繼承基類的所有字段、屬性、事件和接口,所以你只需要關注你想添加到派生的類中的成員: Class Person
  Public FirstName As String
  Public LastName As String
  Function CompleteName() As String
  Return FirstName & " " & LastName
  End Function
  End Class
  Class Customer
  Inherits Person
  ' a new fIEld and a new method
  Public Title As String
  Function ReverseName() As String
  Return LastName & ", " & FirstName
  End Function
  End Class
  
  更好的是,如果你期望派生的類有不同的行為,你還可以覆蓋基類中的屬性或方法。例如,你可能想讓Customer.CompleteName方法以“Mr. John Doe”的形式返回一個字符串。你必須做兩件事來覆蓋一個成員:將基類的成員標記為Overridable,使它成為一個虛擬的成員,用關鍵字Overrides來標記派生的類的成員: ' in Person class
  Overridable Function CompleteName() As String
  ' ...(as before)
  End Function
  
  ' in Customer class
  Overrides Function CompleteName() _
  As String
  Return Title & " " & FirstName _
  & " "& LastName
  End Function
  
  重用基類中的代碼
  Visual Studio .Net為我們在一個派生的類中寫被覆蓋的成員的代碼提供了一個很好的捷徑:在編輯窗口上方最左邊的ComboBox中選擇類名字下的(Overrides)成員,然後在最右邊的ComboBox中選擇你想覆蓋的成員(見圖1)。在派生的類中你不需要用關鍵字Overridable,因為被覆蓋的方法本身就是可以被覆蓋的。如果你出於某種原因想停止進一步覆蓋那個方法,你必須用關鍵字NotOverridable標記它: ' derived classes can't override this
  NotOverridable Overrides Function _
  CompleteName()As String
  ' ...
  End Function
  
  重新定義的方法中的代碼通常從重用基類的方法中的代碼中受益——例如,
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved