1. 程式人生 > >VB.net學習筆記(六)VB.net的物件

VB.net學習筆記(六)VB.net的物件

1、System.Object

       每個變數、控制元件、窗體都繼承了System.Object

2、物件的宣告與例項化

     簡單說宣告,只是說明型別,例項化說明在記憶體中分配了空間。

      用New來建立物件,得到類的一個新例項

      下面有5種例項化形式,其中3較為標準且可讀化高。

        Dim a As theClass   '1,用兩語句來建立例項,先宣告再例項化
        a = New theClass()

        Dim b As New theClass()  '2,僅一個語句例項化

        Dim c As theClass = New theClass() '3,僅用一個語句例項化,更能表明型別與建立,在介面/繼承上更好用


        doSomeThing(New theClass())  ' 4,引數中建立例項


        doSomeThing(New theClass().getValue()) '5,引數中建立的同時呼叫其方法
        

3、物件引用

     通常使用物件都是使用物件的引用。物件的引用(物件變數)本質上就是物件的指標就同C++的指標一樣。

     當用New建立一個物件時,就會將物件的引用(指標)儲存到一個變數中。

     下面是物件a,和b賦值時本質情況,在C++中被稱為淺複製


4、取消物件

      給一個物件引用賦值為Nothing時,就取消了這個物件的引用。

      經實驗,Nothing實際上儲存的是0,和C++一樣給一個物件變數設定為0時,就取消它指向堆中分配的空間。

       這時.Net會知道:這個物件不再需要,執行庫會在某時刻銷燬該物件,收回記憶體及資源。因此在.Net刪除物件

       之前,Framework會為該物件呼叫Finalize方法。

5、前期繫結與後期繫結

      前期繫結:編譯時就知道型別,故能準確地分配空間指定大小,執行速度快

      後期繫結:編譯時不知道,只有執行時才知道,它提供了靈活性(但IntelliSense也就失效了),由於是執行時動態

                           分配所以速度慢。

       後期繫結容易出錯,所以一般要配合Try....Catch...進行處理異常情況

       (option Strict  off就是可以後期繫結,預設)

6、型別轉換

     隱式轉換與顯式轉換

     Cint,Clong....等是為了相容由VB6轉向VB.net,這並不是最佳的方式。

     VB.net提供了幾個顯式轉換。

     (1)Convert轉換類

        可用Convert.ToLong(變數)之類,把變數轉換成Long型

        此類只能將已經一些基本型別已經明確知道型別納入到其中的函式,並不能代表全部。

       注意:1、如果出現錯誤,將丟擲異常。比如將負數轉為非負的UInt32

                    2、共享方法MaxValue,MinValue勿需引數就可得到值如:Long.MaxValue

      (2)Parse、TryParse方法

         僅用於值型別,將字串轉為相應的數值型別

                    result=Long.Parse("100")

          如果失敗,將丟擲異常,而異常會消耗額外的系統資源,影響效能。

          於是TryParse出場,它封裝了異常處理,只返回是否成功的邏輯值,

           成功,返回True,失敗為False,常用於轉換前判斷。

          dim a  as Long

           if   Long.TryParse("100", Long) then

                  b=a

            end if

         (3)Ctype函式

         預設Option  Strict是關閉的,因此是可以隱式轉換,但如果開啟了,一些轉換就不能進行,就可以用Ctype指定。
         dim a as object=c
         dim b as string
         b=a     '若啟option strict將出錯,這時須指定為Ctype(a,string)


         CType若失敗,將引發異常




       (4)DirectCast( a, b)函式
         把a轉為b型別,僅用於引用型別且用於假定可以直接轉換的,不能對轉換資料執行額外的處理,即不具有主動性。
         常用於具有繼承關係的型別。失敗將產生異常。


          如果說CType是智慧體,可以轉換任意型別,那麼DirectCast只能轉換具用繼承判斷的引用型






          (5)TryCast
             TryCast與DirectCast類似,不同的時,因封裝了異常處理,它不會丟擲異常。
             如果成功,返回正確轉換後的型別;
             如果失敗,返回Nothing
             
             TryCast用於繼承等的引用型別,不會丟擲異常。

===========================================================================================

物件是由類產生,物件是類的一個例項。

1、建立類

      用Class關鍵字來建立類

      Pulbic  Class  Person

              ...................'Code

      End Class

     最常見的是每個檔案只包含一個類。

     注意:我們可以發現一個簡單的窗體程式就只有一個類,而沒有什麼例項產生,或執行。

                 這是什麼原因呢?

      原來:首先啟動窗體時候已經例項化了一個物件,該物件會有一個執行緒,通常我們稱為UI始終監視資訊泵系統,

                 如果接受到類似的拖動,點選,重繪資訊,訊息泵就會去通知UI,讓UI來處理

2、欄位

      欄位即C++的資料成員,是用來儲存資料的。每產生一個物件都會產生一個欄位的副本。

      注意關鍵字的作用域 :

          Private      私有,只能用於類中程式碼

          Public       公有,類內類外的任何程式集的的任何專案都可使用

          Protected   保護,只用於該類繼承的類

          Friend       友元,只能用於專案或元件的程式碼

          Protected Friend    用於專案或元件的程式碼以及專案內或專案外從該類繼承的類

Public Class People
    Private mName As String   '欄位,即資料成員
    Private mBirthday As Date

End Class


3、方法

        方法是類的方法成員,由sub或function等來完成對資料成員的操作,或對外部的一處理。

        sub  是不用返回值

        function   需返回值,返回值在程式碼中用return來指明,或者用方法名(函式名)賦值取得

    Public Function Age() As Int32
        Return CInt(DateDiff(DateInterval.Year, mBirthday, Now())) '用return返回值
    End Function

    Public Function Age() As Int32
        Age = CInt(DateDiff(DateInterval.Year, mBirthday, Now())) '用方法名取得返回值
    End Function


4、方法的作用域

       方法前面的關鍵字用來指明方法的作用域

        它與欄位的作用域一樣。比如:

        Friend的方法,表明對於 專案內的程式碼這是物件介面的一部分,但使用該程式集的其它應用程式或專案不能呼叫。

5、方法的引數

     引數與前面的sub,Function一樣。

     對於值傳遞用byval,或用引用傳遞使用ByRef,這樣在方法中更改其值,可使原值發生變化。     

    Public Class People
        Private mName As String   '欄位,即資料成員
        Private mBirthday As Date
        Private mTotalDistance As Int32

        Public Sub Walk(ByVal distance As Int32) '若需改變外部distance值,這裡可改byval為byref
            mTotalDistance += distance
        End Sub

        Public Function Age() As Int32
            Return CInt(DateDiff(DateInterval.Year, mBirthday, Now())) '用return返回值
        End Function

    End Class


6、屬性

     .net提供了一種特殊的方法,稱屬性,使用關鍵字Property。

     本質上它還是方法,只是為了分類、理解更容易,結合前面的欄位(資料成員),提供一種新的方法稱屬性。

      比如前面的欄位mName ,如果設定成Public,原理上可以的,但和我們設計類的封閉性違背。

      這種情況一般用一個方法來程式碼對欄位的直接操作,而原欄位設定成Private,就完善了對資料封裝的概念。

      由於常用這個的方法來操作較為頻繁,於是設計成一個Property屬性(方法)來代替,用Get實現讀取欄位,

      用Set來實現給欄位賦值。

      這樣有幾個好處:

       1、完善了類的封裝;

        2、實現了對欄位值的過濾,比如賦值時,如果是負數(不允許為負時)可以在程式碼中提示。

        3、細化了欄位的讀和寫,有時只准讀,有時只准寫,這樣分類進行限制。

        4、對範圍進行限制,有些只准在專案內使用,有些可以。(用Friend來限制)

      例:下面是一個屬性的定義

    Public Property mName() As String
        Get
            Return mName
        End Get
        Set(value As String)
            mName = value
        End Set
    End Property

      注意:1、屬性名和欄位名各不相關,可以相同,也可以不同(最好設定不同,例中為相同)

                        儘管屬性中操作的是一個(或多個)欄位,只有明白內部的程式碼才能知道對應的是哪個欄位。

                        而在物件中顯示屬性成員的名字時,是屬性名而不是欄位名!!!

                         例中mName屬性與欄位mName並不相關,對生成的物件成員中顯示的屬性名。

                   2、對於一般不須限制的屬性可以直接用下面簡化成一句即可。  

Public Property mName() As String

                           效果與 Public  mName as String一樣

                   這個功能叫“自動實現的屬性”。MSDN描述如下:

                 “自動實現的屬性”使您可以快速指定類的屬性,而無需編寫程式碼對該屬性執行 Get 和 Set 操作。
                 通過自動實現的屬性,可在一行中宣告一個包含預設值的屬性。

Public Property Name As String
Public Property Owner As String = "DefaultName"
Public Property Items As New List(Of String) From {"M", "T", "W"}
Public Property ID As New Guid()
               在宣告自動實現的屬性時,Visual Basic 會自動建立一個隱藏的私有欄位(稱為“支援欄位”)來包含該屬性的值。

               支援欄位名稱是在自動實現的屬性的名稱前面加下劃線 (_)。 

              例如,如果宣告一個名為 ID 的自動實現的屬性,則支援欄位的名稱為 _ID。

              如果有一個類成員的名稱也是 _ID,則會產生命名衝突並且 Visual Basic 會報告編譯器錯誤。


            此外,支援欄位還具有下列特性:
                支援欄位的訪問修飾符始終為 Private,即使該屬性本身具有不同的訪問級別(如 Public)也是如此。
               如果該屬性標記為 Shared,則支援欄位也是共享的。
              為該屬性指定的特性不應用於支援欄位。
                可從類中的程式碼以及從監視視窗等除錯工具中訪問支援欄位。 但是,支援欄位不會顯示在 IntelliSense 文字完成列表中。

           必須改用標準的“擴充套件”屬性語法(此時不能用自動實現的屬性功能)。
          如果要執行下列任一操作,則必須使用擴充套件屬性定義語法:
                 向屬性的 Get 或 Set 過程新增程式碼,如用於驗證 Set 過程中的傳入值的程式碼。 例如,在設定屬性值之前,您可能希望驗證一個表示電話號碼的字串是否包含所需數目的數字。
                為 Get 和 Set 過程指定不同的可訪問性。 例如,您可能希望將 Set 過程設為 Private,將 Get 過程設為 Public。
                建立 WriteOnly 或 ReadOnly 屬性。
                使用引數化屬性(包括 Default 屬性)。 若要為屬性指定引數,或者為 Set 過程指定附加引數,必須宣告擴充套件屬性。
                為支援欄位設定特性,或者更改支援欄位的訪問級別。
               為支援欄位提供 XML 註釋。
              

        下例是限制賦值時,只能在專案內生效,專案外不能賦值。

    Public Property mName() As String
        Get
            Return mName
        End Get
        Friend Set(value As String) '僅限於專案內使用
            mName = value
        End Set
    End Property

7、引數化屬性

      屬性有可能是單一值,也可是多個值(屬性陣列、引數化屬性)。

      這樣,它可以為某些設定一個可選範圍,或者成一個數組,如:電話號碼可儲存多值。

     為此,我們可以把mPhone電話號碼屬性設定成雜湊表型別。

     例:   引數是“索引”

   Private mPhones As New Hashtable '雜湊表類(集合)
    Public Property Phone(ByVal location As String) As String '引數類似索引在雜湊表中定位
        Get
            Return mPhones.Item(location)
        End Get
        Set(value As String)
            If mPhones.ContainsKey(location) Then '判斷是否已經有此索引
                mPhones.Item(location) = value    '有,直接更新值
            Else
                mPhones.Add(location, value)       '無,加入索引及值
            End If
        End Set
    End Property

        注:雜湊表,本質上同陣列相同,都是通過“索引”來取得或設定值。但陣列是“數值”型的索引,而雜湊表索引可以是其它型別

               比如字串,陣列是連線儲存,雜湊表是通過“索引”(關鍵字)對映取得。

                另外,雜湊表比陣列靈活,但更浪費空間。

8、只讀屬性、只寫屬性

        正如前面所說,在Property前加入ReadOnly(只讀)或WriteOnly(只寫),就可限制對屬性的操作。

        如:

         Public  WriteOnly  Property   Amber() as int32

                  set(ByVal  Value  As integer)     ‘只讀,當然只有Set而沒有Get

                              mAmber=Value

                   End Set

           End  Property

9、預設屬性

      物件可以實現預設屬性,用它時,不用指明屬性,會自動賦值或獲取對應的某屬性。

      這時,須用Default來指明某屬性是預設的屬性。例:

    Private mPhones As New Hashtable
    Default Public Property Phone(ByVal location As String) As String '用default表示這個屬性當作物件的預設值
        Get
            Return mPhones.Item(location)
        End Get
        Set(value As String)
            If mPhones.ContainsKey(location) Then
                mPhones.Item(location) = value
            Else
                mPhones.Add(location, value)
            End If
        End Set
    End Property
    '================================================================================
    Dim myPerson As New People
    myPerson.Phone("home")="12345678" '沒有指定為預設屬性時,必須這樣明確指明屬性
    myPerson("home")="12345678"       '一旦指明預設屬性為phone時,可簡化成此句,自動知道是Phone屬性

        預設屬性必須是帶引數的屬性,不帶引數的屬性不能為預設值。

       猜想是不是不帶引數時,VB.net無法判斷是隱式的型別轉換還是給預設屬性進行賦值?對否?