VB.Net中文教程(7) Me參考值 (轉)

worldblog發表於2007-12-06
VB.Net中文教程(7) Me參考值 (轉)[@more@]

請注意 ......
著作權所有人:物澤事業股份有限公司、
  MISOO技術顧問團隊、物件導向雜誌作者、等。
u本摘自 物件導向雜誌、精通物件觀念與技術等書籍著作。
u本檔案僅供您的參閱,請遵守著作權法,不得做其它商業用途。

 

主題:  Me參考值


??????  內容  ??????
v 1. 活用Me參考值
  1.1認識Me參考值
  1.2傳回Me參考值

v 2. 認深入瞭解Me參考值

 


1. 使用Me參考值
1.1 認識Me參考值

  類別之程式成員(Procedure Member) 各含一個Me參考變數﹐它永遠參考到「目前物件」(Current )。目前物件就是正接受並處理訊息之物件。例如﹐

'ex01.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.s
'------------------------------------------------------------------------------
Public Class Fee
  Private amount As Decimal

  Public Sub New(ByVal amt As Decimal)
  Me.amount = amt
  End Sub
  Public Sub disp()
  MessageBox.Show("Amount is " + str( Me.amount ))
  End Sub
End Class
'--------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win FoDesigner.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrs dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click(ByVal sender As Object,
  ByVal e As System.EventArgs)
  Dim a As New Fee(100)
  Dim b As New Fee(80)
  a.disp()
  b.disp()
  End Sub
End Class

此程式輸出如下﹕Amount is 100
  Amount is 80


a 和 b是Fee類別之物件。當計算機指令──
  a.disp()

a 就是目前物件﹐disp()程式裡的Me正參考到物件a。

 
也可看成:
 
  圖1、 Me參考值與目前物件

請注意﹕Me參考到物件a﹐也就是Me與a皆參考到同一個物件。
當計算機執行另一指令── b.disp()時,b 即為目前物件﹐而disp()程式之Me參考正指向物件 b。
 

由於Me正參考到物件b﹐所以Me與b參考到同一個物件。寫程式時﹐宜充分利用Me參考。

 

1.2 程式傳回Me參考值

  在應用上﹐程式常傳回Me參考值﹐可創造奇妙的效果﹐這種效果也是VB的重要特色。希望您能仔細瞭解Me指標之使用場合﹐能讓您寫出完美的程式來﹗現在﹐請看個熟悉的程式──

'ex02.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------
Public Class Money
  Private balance As Decimal
  Public Sub New(ByVal amount As Decimal)
  balance = amount
  End Sub
  Public Sub add(ByVal saving As Decimal)
  balance = balance + saving
  End Sub
  Public Sub Display()
  MessageBox.Show("Balance is " + str(balance))
  End Sub
End Class
'--------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click(ByVal sender As Object,
  ByVal e As System.EventArgs)
  Dim orange As New Money(100)
  orange.add(300)
  orange.add(80)
  orange.Display()
  End Sub
End Class

此程式輸出如下﹕Balance is 480

  Money 類別的 balance資料﹐記錄存款餘額。main()內之物件orange接受兩訊息──add(300)及add(80) ﹐欲存入兩項金額。

 
 
指令──  orange.add(300)
  orange.add(80)

表示﹕先存入 300元再存入80元﹐有先後次序。若上述圖形改為──

 

則更具次序感。於是﹐上述指令相當於──
 
 

這種效果﹐不太陌生吧﹗回憶小學時,班長喊著:「起立、敬禮、坐下」,您不是連續接受到三個訊息嗎?漸漸地﹐您已能設計出像日常生活這般親切之物件了。不過﹐俗語說﹕「萬丈高樓平地起」﹐還是必須先對Me參考有充分了解才行﹗請看個程式──

'ex03.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-----------------------------------------------------------------------------------
Public Class Money
  Private balance As Decimal
  Public Sub New(ByVal amount As Decimal)
  balance = amount
  End Sub
  Public Function add(ByVal saving As Decimal) As Money
  balance = balance + saving
  add = Me
  End Function
  Public Sub Display()
  MessageBox.Show("Balance is " + str(balance))
  End Sub
End Class
'----------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click(ByVal sender As Object, 
  ByVal e As System.EventArgs)
  Dim orange As New Money(100)
  orange.add(300).add(80)
  orange.Display()
  End Sub
End Class

此程式輸出如下﹕Balance is 480
由於Me永遠參考到目前物件﹐此刻Me正參考到物件orange。
 
 
  圖2、  程式傳回目前物件之參考值

oragne物件就是Me所指之物件﹐也可以說Me與orange皆參考到同一個物件。指令──
  add = Me

傳回目前物件之參考值──即orange物件之參考。add() 程式之定義──

 

於是add()把目前物件之參考值Me傳回Form1_Click()。此刻﹐orange.add(300)之值也是參考值,與orange參考到同一個物件。
 

於是,Form1_Click()程式之指令──

 

成為orange物件之別名了。
原來的指令──  orange.add(300).add(80)
相當於──  orange.add(80)

不過﹐此時orange物件之 balance變數值為400元﹐而非原來的100元了。此orange再接受訊息── add(80)﹐其 balance值增加為480 元。orange接到第 2個訊息── add(80)時﹐計算機再執行add() 程式﹐其再度傳回orange的參考值﹐使得整個指令──
 
又成為orange之別名。因之﹐亦能把disp()訊息接於其後﹐如下﹕

'ex04.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------
Public Class Money
  Private balance As Decimal
  Public Sub New(ByVal amount As Decimal)
  balance = amount
  End Sub
  Public Function add(ByVal saving As Decimal) As Money
  balance = balance + saving
  add = Me
  End Function
  Public Sub Display()
  MessageBox.Show("Balance is " + str(balance))
  End Sub
End Class
'-------------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click( ByVal sender As Object,
  ByVal e As System.EventArgs)
  Dim orange As New Money(100)
  orange.add(300).add(80).Display()
  End Sub
End Class

此程式輸出如下﹕Balance is 480
  orange物件接到第 1個訊息──add(300)﹐計算機就執行add()程式,執行到結尾指令﹐傳回Me(即orange物件)參考值。此時Form1_Click()的orange.add(300)就是orange物件之參考值﹐亦即orange.add() 是orange物件之別名﹔則orange和 orange.add(300)重合在一起﹐代表著同一物件──原來的orange物件。

 

  接下來﹐第 2個訊息──add(80)傳給orange.add(300) ﹐相當於傳給orange物件。再度執行到 add()裡的的add = Me指令時﹐又令orange.add(300).add(80) 成為 orange.add(300)之別名﹐即orange之別名﹔於是﹐三者代表同一物件──原來的orange物件。
 
 

  接下來﹐第3個訊息──Display傳給orange.add(300).add(80) ﹐相當於傳給orange物件。
 
於是輸出orange物件內的balance值。
  以程式傳回Me參考值之技巧將應用於許多方面。為了更瞭解這種方法﹐請看個特殊情形── 程式傳回新物件之參考值。此物件不是目前物件,但內容是從目前物件複製而來。這不同於傳回Me參考值的情形﹐兩種用法常令人搞混﹗現在﹐把程式改為──

'ex05.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------
Public Class Money
  Private balance As Decimal
  Public Sub New(ByVal amount As Decimal)
  balance = amount
  End Sub
  Public Function add(ByVal saving As Decimal) As Money
  Dim newobj As Money
  newobj = New Money( balance + saving )
  add = newobj
  End Function
  Public Sub Display()
  MessageBox.Show("Balance is " + str(balance))
  End Sub
End Class
'-------------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  .......
#End Region
  Protected Sub Form1_Click( ByVal sender As Object,
  ByVal e As System.EventArgs)
  Dim orange As New Money(100)
  orange.add(300).add(80).Display()
  End Sub
End Class

此程式輸出如下﹕Balance is 480

  當orange物件接到第 1個訊息──add(300)﹐計算機就執行add()程式﹐誕生一個Money類別的新物件﹐把目前物件內容(即orange物件之值)複製一份給Form1_Click()。這份複製就是orange.add(300)之值。
 
  orange.add(300) 即為複製回來的那份物件﹐並非原來的orange物件。當訊息──add(80)傳給orange.add(300)所代表的物件時﹐計算機就執行add()﹐此時目前物件是orange.add(300) 而非原來的orange。執行時﹐又把目前物件──orange.add(300)內容複製一份給新誕生的物件,傳回給Form1_Click()程式﹐這份複製就是orange.add(300).add(80) 之值。

 

  由於每回執行add()就產生一份新物件(雖然內容相同﹐但佔不同的空間)﹐其後的訊息皆傳給add()所誕生之新物件﹐而非orange物件,所以這些訊息皆不影響原來orange物件之內容。
  請注意﹕Display()並未傳回物件之參考值﹐則Display()訊息之後不得再接其它訊息了。所以﹐如果Form1_Click()程式改寫如下,那就錯了──

Protected Sub Form1_Click( ByVal sender As Object,
  ByVal e As System.EventArgs)
  Dim orange As New Money(100)
  orange.add(300).Display().add(80)  'Error!
  End Sub
End Class

因Display()不傳回物件之參考值﹐則指令──
 
其後之訊息──add(80) 是錯的。如何改正呢﹖很簡單﹐只需叫Display()程式傳回 Me(目前物件之參考值)或新物件之參考值即可﹐如下﹕

'ex06.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-------------------------------------------------------------------------------------
Public Class Money
  Private balance As Decimal
  Public Sub New(ByVal amount As Decimal)
  balance = amount
  End Sub
  Public Function add(ByVal saving As Decimal) As Money
  Dim newobj As Money
  newobj = New Money( balance + saving )
  add = newobj
  End Function
  Public Function Display() As Money
  MessageBox.Show("Balance is " + str(balance))
  Display = Me
  End Function
End Class
'-----------------------------------------------------------------------------------
Public Class Form1
  Inherits System.WinForms.Form
 
  Public Sub New()
  MyBase.New()
  Form1 = Me
  'This call is required by the Win Form Designer.
  InitializeComponent()
  'TODO: Add any initialization after the InitializeComponent() call
  End Sub
  'Form overrides dispose to clean up the component list.
  Public Overrides Sub Dispose()
  MyBase.Dispose()
  components.Dispose()
  End Sub
#Region " Windows Form Designer generated code "
  ........
#End Region
  Protected Sub Form1_Click(ByVal sender As Object,
  ByVal e As System.EventArgs)
  Dim orange As New Money(100)
  orange.Display().add(300).Display().add(80).Display()
  End Sub
End Class

此程式輸出﹕
  Balance is 100
  Balance is 400
  Balance is 480

此程式中﹐orange先接受Display()訊息﹐印出存款額﹔再接受add(300)訊息﹐使存款額提高 300元﹐再接受Display()訊息﹐依序下去。Display()傳回來目前物件orange之參考值,add()則傳回新誕生物件之參考值。

 

2. 深入瞭解Me參考

  VB在編譯時﹐會自動為程式成員產生Me參考變數﹐並令Me固定參考到目前物件(Current Object)。於此將細談VB如何產生Me參考變數﹐讓您更能深刻了解Me參考變數的特性和角色。首先﹐VB在編譯程式成員時﹐會暗中偷加上1 個參考引數──Me﹐成為該程式成員的第1 個引數。例如﹕


  Class Person
  Private name As String
  Priavte age As Integer
  Public Sun New(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  End Sub
  Public Sub Display()
  Messagebox.Show( name  + ",  " + str( age ) )
  End Sub
  End Class

在編譯此程式時﹐VB會將偷加上Me參考變數如下﹕

  Class Person
  Private name As String
  Priavte age As Integer
  Public Sun New( ByVal Me As Person, ByVal na As String,
  ByVal a As Integer)
  Me.name = na
  Me.age = a
  End Sub
  Public Sub Display(ByVal Me As Person)
  Messagebox.Show( Me.name  + ",  " + str( Me.age ) )
  End Sub
  End Class

無論是在New()或Display()程式裡﹐Me皆固定參考到目前物件﹐您不能改變Me之值。接下來﹐請看如何令Me參考到目前物件﹖假如有個Form1_Click()程式如下﹕
 
Sub Form1_Click( .... )
  Dim x As New Person("Tom", 26)
  x.Display()
End Sub


  VB在編譯時﹐會把指令──x.Display()轉換為﹕
  Person_Display(x)

意謂著﹕呼叫Person類別的Display()程式來處理x 物件之內容。在呼叫這程式時﹐就把x參考值傳遞給Display()程式裡的Me引數﹐如下﹕
 

於是﹐Me就固定指向x物件了﹐而這x 物件就是我們欲處理之物件﹐亦
即就是目前物件了。請再看個例子吧﹗若Person類別改為﹕

  Class Person
  Private name As String
  Priavte age As Integer
  Public Sun New(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  End Sub
  Public Sub Print()
  Me.Display()
  End Sub
  Public Sub Display()
  Messagebox.Show( name  + ",  " + str( age ) )
  End Sub
  End Class

 

 

則VB會為這3 個程式成員加上Me參考值。其中Print()程式轉換如下﹕
 
  Public Sub Print(ByVal Me As Person)
  Person_Display( Me )
  End Sub

上述的Me.Display()轉換為Person_Display( Me )之後﹐就把這Print()內的Me值傳給了Display()內的Me了﹐此時兩個程式內的Me皆參考到目前物件了。
  以上所提的一般程式成員並不包括共享程式成員(Shared Member Function)。還記得嗎﹖共享程式成員的目的是﹕處理有關整個類別的事情﹐而不是用來處理物件之內容。在另一方面﹐Me參考到目前物件﹐一般程式成員經由Me來存取目前物件之內容。既然共享程式成員不需存取某特定物件之值﹐當然就不需要Me參考變數了﹐因之VB並不會為共享程式成員偷加上Me參考變數。簡而言之﹐VB的規則是──

  「VB編譯時﹐並不會為共享程式成員加上Me參考變數﹐所以
  共享程式成員裡沒有Me參考變數﹐也就無法存取物件之內容」

如前面所述﹐在呼叫一般程式成員時﹐必須把目前物件之參考值傳遞過去給該程式成員。但共享程式成員裡並無Me參考﹐所以無法呼叫一般程式成員。可得知VB的規則──
  「共享程式成員不能呼叫一般程式成員﹐但可呼叫別的共享程式成員」

反之﹐一般程式成員卻可呼叫共享程式成員。例如﹕

 

 

  Class Person
  Private name As String
  Priavte age As Integer
  Shared plast As Person

  Public Sun New(ByVal na As String, ByVal a As Integer)
  name = na
  age = a
  plast = Me
  End Sub
  Shared Sub DispLast()
  plast.Display()
  'Display()  Error !!
  End Sub
  Public Sub Print()
  DispLast()
  End Sub
  Public Sub Display()
  Messagebox.Show( name  + ",  " + str( age ) )
  End Sub
  End Class

Display()是一般程式成員﹐共享程式成員DispLast()不能直接呼叫Display()程式如下﹕
  Shared Sub DispLast()
  Display()  Error !!
  End Sub

因為VB會將之轉換為──

  Shared Sub DispLast()
  Person_Display( Me )  Error !!
  End Sub

但DispLast()是共享程式成員﹐並無Me參考變數﹐所以錯了。至於Print()
呼叫DispLast()﹐VB將之轉換為──

  Public Sub Print( ByVal Me As Person )
  Person_DispLast()
  End Sub

  雖然Print() 內有Me參考﹐但DispLast()是靜態程式成員並不需要Me
﹐Print() 並未把Me傳給DispLast()﹐這是對的。n


 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988985/,如需轉載,請註明出處,否則將追究法律責任。

相關文章