刚刚发现类还没有写完,还有一个比较大的部分:属性(Property)。
Property在Java和C++里面都是闻所未闻的。通常认为类当中只要有成员和方法就行了。至于属性呢,当使用的时候,属性看起来就像成员,属性和成员有很多相似之处。但是属性有更多独特之处,它可以说是VB的一大特色。我的理解就是属性是为了更好的对成员进行处理而存在的。
属性是这样一种东西,它看起来像是成员,但本质上它是函数。属性的定义是这样的:
public property MyProperty() as Object 'MyProperty是属性的名字
Get '这个地方不能打括号
return mvarMyProperty
end Get
Set(Byval Value as Object)
mvarMyProperty = Value
end Set
end Property
可以看到,属性其实是由两个函数组成的:Get 和 Set()。当我们读取属性的时候,它就调用Get,所以Get里面必须有return语句;当设置属性的时候,它就调用Set(),所以Set()是带参数的。当外界读取MyProperty的时候,MyProperty就返回mvarMyProperty。mvarMyProperty是事先声明好的变量。当外界设置MyProperty的时候,所赋的值就赋给mvarMyProperty。在这里,mvar-是VB6中缺省使用的前缀,表明这是一个存放属性的变量。
到这里你可能理解了,属性本身不保存数据,它通过另一个变量来读写。但是这又是一件奇怪的事:有必要这么麻烦吗?我直接写:
public MyProperty As Object
不是更简单吗?
这里有一个简单的解释:通过Property,我们可以隐藏真实的成员,比如mvarMyProperty我们就可以定义为:
private mvarMyProperty As Object
这样一来,外界就看不到mvarMyProperty,只能看到MyProperty。当外界对其进行读写的时候,中间就有一个处理过程,用来避免对成员的不正确的赋值。其实对于这种情况,java和C++也有类似的做法,就是使用SetMyProperty()函数和GetMyProperty()函数。VB用Property这种特殊的格式将它们做到一起,显得更简单方便了。
好了,到这里,你不想看看完整的例子吗?这里重新写了一个Human类,当中有一个Age(年龄)属性。我们看看它是怎样阻止把一个人的年龄设为负值的:
imports System
public module MyModule
sub Main
dim LaoWang as new Human
LaoWang.Name = "老王"
LaoWang.Age = 52
LaoWang.Age = 330 '这句话有没有把老王的年龄设为330岁呢?看看下一句的结果就知道了。
Console.WriteLine("{0}现在{1}岁。", LaoWang.Name, LaoWang.Age)
Console.ReadLine()
end sub
end module
public class Human
public Name as String
dim mvarAge as integer '这里没有指明是public还是private,因为缺省状态是private
public property Age() as integer
Get
return mvarAge
end Get
Set(Byval Value as integer)
if Value<=0 or Value>=200 then '通常年龄不应该小于1或大于200
Console.WriteLine(Value & "岁?我死了吗?")
else
mvarAge = value
end if
end set
end property
end class
到这里你应该闭目养神一会儿:原来属性是这样子的啊!
但是话题还没有完。
比如说,如果成员是一个数组,我该怎样为它建立属性呢?为当中的每一个元素建立吗?那数组大小变化了怎么办?Property才不会这么蠢。我们举个例子。比方我们给Human类添加一个数组成员Children,表示一个人有多少个孩子。我们先定义mvarChildren:
dim mvarChildren() as Human
为其建立属性有两种方式。一种是直接将属性的类型设为数组:
public property Children() as Human()
Get
return mvarChildren
end Get
Set(Byval Value as Human())
mvarChildren = value
end Set
end property
那么我们就可以像使用数组一样来使用这个属性了。
另一种是在读取属性的时候传入参数index:
Public Property Children(ByVal index As Integer) As Human
Get
Return mvarChildren(index)
End Get
Set(ByVal Value As Human)
mvarChildren(index) = Value
End Set
End Property
这样可以对传入的下标进行检查。
这里提到读取属性的时候可以给参数。这是很有趣的一个东西。比如老王有3个小孩,其中一个叫“王华”。我想根据名字来得到这个小孩,我可以写一个函数
public function GetChildByName(Byval Name as string) as Human '内容省略了
然后调用
LaoWang.GetChildByName("王华")
就可以了。
要写成属性的话,我们可以这样写:
public property Child(byval Name as string) as Human
Get
return getChildByName(Name)
end get
set(byval Value as Human)
getChildByName(Name) = Value
end Set
end property
这样,我们就可以直接使用:
LaoWang.Child("王华").Age = 20
这样是不是很方便啊?