参考|教程|中文
1. 使用Me参考值
1.1 认识Me参考值
类别之程序成员(Procedure Member) 各含一个Me参考变量 它永远参考到「目前对象」(Current Object)。目前对象就是正接受并处理讯息之对象。例如
'ex01.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------
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 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 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指针之使用场合 能让您写出完美的OOP程序来 现在 请看个熟悉的程序──
'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