了解程序的种类
在vb.net 中有三种程序(procedure),分别是一般程序、事件程序以及属性程序。属性程序最主要是在建立对象类别时定义对象的属性,超过我们所要讨论的范围,这里的重点放在一般程序以及事件程序。一般程序是指sub 或function,可以帮助我们将复杂的程序做成许多容易管理的单元,至于sub 和function 的差别我们后面再来了解。而事件程序会自动触发,用来响应系统或使用者所执行的动作。例如当网页被加载时会触发init 这个事件,并会自动执行page_init()这个事件程序。
一般程序
一般程序要被其它程序呼叫才能执行,它可以帮助我们将复杂的程序代码分成容易管理的单元,并且可被不同的程序所叫用。一般程序有两种,分别为sub 以及function。
sub
以sub 方式写成的程序没有传回值,也就是不会传回执行的结果。我们先看看sub 的语法:
sub 程序名称(参数1 as 型态, 参数2 as 型态,...)
程序代码...
end sub
另外,asp.net 规定所有的程序必需另外放在script 标注中,如下所示:


被script 标注所围起来的部分表示为程序, 不管是一般程序或是事件程序都必需被script 标注所围起来,程序只有被呼叫或是发生一件事件的时候才会被执行。script 标注的language 属性可以设定程序要使用的语言,这里我们所使用的语言为vb.net,所以设定值为vb;runat 属性值为server,表示这些程序会在server 端执行。我们要执行程序的时候,只要直接输入程序的名称并且要加上小括号即可;我们称使用程序的动作为「呼叫」。我们在呼叫程序时,主程序的执行会暂时停止,并跳到程序中继续执行,等遇到end sub 时表示程序执行完毕,程序的执行便跳回到刚刚呼叫的地方继续执行下一个叙述。例如:


程序可以重复再利用,我们可以多次呼叫使用同一个程序,这样不但好管理而且比较简洁。上述程序执行的结果为:

参数的传递
若有要一并传送的参数,则可以在小括号内输入。我们可以将变量的内容或是直接将数据传入程序内做处理,若参数为一个以上,则使用逗号来做分隔。


由于我们的程序要接收参数,所以就必需在宣告程序的时候,在小括号内宣告一个变量来接受参数。所以在主程序执行sayhello("煌章")时,即将参数"煌章"传递给程序。这时候我们在宣告程序时,要在小括号内宣告变量来接收。在小括号内宣告变量不需要加dim 关键词,直接指定变量名称及数据型态即可。

接下来我们来撰写传递两个参数的程序。参数若是有两个以上,在宣告的时候必需用逗号来做区隔,而且在传递参数时参数的顺序也要对应正确。下面的例子我们将刚刚的英制单位转公制单位的程序改成以呼叫程序的方式执行:



function 程序
以function 的方式写成的程序有传回值,也就是会传回执行的结果,所以在呼叫function 的时候必需用变量或对象的属性来接收。function 的语法:

function 程序也是一样必需被script 标注所括起来。以function 关键词所宣告的程序,表示是有传回值的function 程序。function 程序一样可以接收参数,我们将处理完的结果利用return关键词传回。下面的例子是将摄氏温度转换成华式温度,我们知道其转换的公式为f=(c×(9/5))+32:



function 一样可以接受参数,可以让我们在呼叫function 的时候顺便将要处理的数据或必需的参数一并传递给function 处理,等function 将数据处理完毕后,则利用return 关键词将结果传回至原来呼叫function 的地方。由于function 有传回值,所以我们在呼叫function 时必需用变量或对象的属性来接收其执行结果。另外要特别注意一点,那就是接收传回值的变量其数据型态要和传回值的数据型态相符合,如果不符合则可以使用转换函式进行数据型态的转换。以下为在浏览器输入http://127.0.0.1/cr/ch03/ex09.aspx?c=30 的执行结果:

传值及传址
参数的传递有两种情形:一种是传递变量的值,另一种是传递变量的地址。上述两种情形称为传值(by value)或传址(by reference)。传递参数时要指定以传值或传址的方式来传递,只要在宣告程序时在要接收参数的变量前加上关键词byval(传值)或是byref(传址)即可。vb.net 的程序对于参数的传递预设是以传值的方式执行,所以如果要以传值的方式传递参数,则byval 关键词可以省略。什么是传递值及传递地址呢?我们来看下列的例子:
<html>
<%
dim shta as short
shta=100
myproca(shta)
response.write("传值后的shta 变数值:" & cstr(shta) & "<br>")
myprocb(shta)
response.write("传址后的shta 变数值:" & cstr(shta))
%>
<script language="vb" runat="server">
sub myproca(byval shtb as short)
shtb=10
end sub
sub myprocb(byref shtb as short)
shtb=10
end sub
<script>
</html>

上述程序总共有两个sub 程序,分别为myproca 以及myprocb。这两个程序都宣告了一个精简整数型态的变量shtb,分别以传值以及传址的方式来接收参数,然后将shtb 的值填入整数10。而在主程序中有个精简整数型态的变量shta,我们将100 填入变量shta 之后分别呼叫myproca以及myprocb,并将变量shta 当作参数传进程序中。结果以传值的方式传递参数的myproca接收到的是shta 的值100,并将接收到的100 存入变数shtb 中。所以我们将变量shtb 变量内的值100 改成10,并不会影响传递进来的变量shta,shta 的值还是100。

执行完myproca 后接下来我们呼叫myprocb,并以传址的方式将参数shta 传入程序中。此时我们所传递的不是值100,而是shta 所在的内存位置。所以shtb 所接收的信息为一个内存地址,任何程序叙述要存取变量shtb 的值时,会读到shtb 内所存放的内存地址,此时程序会将变量shtb 所指到的内存地址进行存取。因为变量shta 以及变量shtb 所参考到的内存地址是同一块,所以当我们改变shtb 的值时,就是改变shta 的内容,变量shta 当然会受影响。故原来变量shta的值为100,后来变数shtb 被填入10 后,变量shta 的内容也改变了。

程序的负载
vb.net 也支持程序的负载。负载就是可以宣告许多名称一样的程序,但是接收不同的参数,并可以视使用者的使用情形决定由哪个程序动作。我们在呼叫程序时,程序会自动依不同的执行条件来呼叫不同的程序。支持负载的程序其宣告语法如下所示:
overloads sub|function 程序名称(参数1 as 型态, 参数2 as 型态,...)
叙述..
.
end sub|function
下列范例中我们负载了四个程序。这四个程序会依照使用者呼叫程序时,所输入的参数而自动执
行相对应的程序。
<html>
<%
dim strrev as string
test("字符串一") '输入一个字符串数据, 执行第一个对应的程序
test(12345) '输入一个数值数据, 执行第二个对应的程序
test(12345,12345) '输入两个数值数据, 执行第三个对应的程序
test("字符串一","字符串二") '输入两个字符串数据, 执行第四个对应的
程序
strrev=test("字符串一","字符串二") '输入两个字符串数据, 并用指定运
算子将执行
'结果存入指定变量, 执行第四个对应的程序
%>
<script language="vb" runat="server">
'输入一个字符串时启动下列程序
overloads sub test(byval stra as string)
response.write("这是第一个程序: 您传来的数据是字符串<br>")
end sub
'输入一个数值时启动下列程序
overloads sub test(byval deca as decimal)
response.write("这是第二个程序: 您传来的资料是数值" & "<br>")
end sub
'输入两个字符串时启动下列程序
overloads sub test(byval deca as decimal, byval decb as decimal)
response.write("这是第三个程序: 您传来的资料是两个数值<br>")
end sub
'输入两个数值, 并用指定运算子接收执行结果时启动下列程序
overloads function test(byval stra as string, byval strb as string)
response.write("这是第四个程序: 您传来的数据是两个字符串" & "<br>")
return stra & strb '将字符串连结后传回
end function
</script>
</html>
event 程序
前面我们提过,事件(event)是对象所认识的动作。对动态网页来说,一页动态网页就是一个page 对象。网页在执行时会发生许多事件,这时候我们就可以撰写发生事件时所要执行的动作;例如网页每次在加载时会先发生init 事件,然后再发生load 事件,最后网页内容全部下载完毕时则会发生unload 事件。我们可以利用init 事件或是load 事件来设定对象的属性值,或是先将要处理的数据从数据库读取出来;最后利用unload 事件将使用完毕对象清除,或是将连到数据库的连结关闭,我们一般都是利用load 事件来执行一些初值设定的动作。每一种对象所认识的事件不一样,微软在设计这些对象的时候已经规划好对象所认识的事件有哪些。关于对象认识哪些事件,我们在后面章节有详细的介绍。以下为事件程序的语法:
sub 对象名称_事件名(参数1 as 型态, 参数2 as 型态,...)
程序代码...
end sub
事件程序一样必需被script 标注括起来,事件程序是以sub 关键词所宣告的程序,必需指明希望响应哪个对象所发生的事件,而对象和事件之间要用底线来做分隔。事件程序一样可以接收参数,这些参数由系统所提供,表示发生某个事件时的一些状态。下面这个例子为响应网页执行时所触发的load 事件:
<html>
<%
response.write("事件发生后")
%>
<script language="vb" runat="server">
sub page_load()
response.write("网页在加载时发生load 事件, 即自动执行本程序<br>")
end sub
</script>
</html>

网页在载入时会触发load 事件。由于网页是page 对象,所以在触发load 事件时程序会到script标注中寻找名称为page_load 的事件程序,若找到此事件程序则执行,若没有找到则不执行。事件程序执行完毕后,程序会回到正常的程序中继续执行程序,等所有的数据下载完毕后即触发unload 事件。由于unload 事件最主要的工作是做一些收尾,并且是在所有数据完成下载后触发,所以不可以使用response.write() 方法将数据再输出到浏览器,否则会发生错误。
