VB.NET语法基础
在进行ASP.NET程序设计之前,首先要选择一种ASP.NET编程语言。ASP.NET的默认语言是Visual Basic.NET,当然也可以使用C#。本书主要介绍Visual Basic.NET,并且书中所有的例子都用Visual Basic.NET来编写。
本章介绍一些Visual Basic.NET的初步知识,关于VB.NET的高级编程知识请读者参阅其他相关图书。
Visual Basic.NET是继Visual Basic 6.0之后新发布的Visual Basic的全新版本。如果您是一个Visual Basic.NET的高手的话,可以跳过这一部分,从第3章开始学习。
学完本章后,读者将能够:
(1) 了解为什么选择VB.NET作为ASP.NET程序设计的首选语言;
(2) 了解变量、常量和表达式的知识;
(3) 会使用条件、循环语句;
(4) 了解如何使用过程和函数。
2.1 编程语言的选择
由于ASP.NET只是一个程序设计环境,要在这个环境中进行程序设计,必须选择一种语言。在早期的ASP中,默认使用的语言是VBScript脚本语言。由于.NET Framework已经支持VB等非脚本的高级语言,所以完全没有必要再去使用VBScript,但是原来用VBScript写的程序在ASP.NET中仍然可以执行,因为.NET环境仍然支持VBScript的语法。
2.1.1 .NET支持的语言
.NET为用户提供了三种程序设计语言:Visual Basic.NET、C#和Jscript。本节分别介绍这三种语言。
Visual Basic.NET是VB最新的版本,从功能和性能上讲可以说有了很大的飞跃。首先,早期的VB版本不完全支持面向对象的程序设计,由于它不支持对象的继承和重载,所以产生了很多问题。另外,早期的VB版本无法创建多线程的应用程序,这样就不能够充分利用机器的资源,也不能很好地提高应用程序的执行效率。但是现在,由于VB.NET使用了CLR,这些问题都很好地得到了解决。
对于C#,可以认为它是在C、C++的基础上创立的一种新的语言。它继承了C++的优异功能,去除了在.NET环境中没有用处的类型定义、模板等功能,使得C#与C++相比,更加易于使用,同时效率也大大提高。
与VB.NET一样,JScript.NET也是从JScript发展而来的。JScript.NET是完全用C#重新编写的,它支持类型和继承性,并且是完全编译执行的。为了保证原有的JScript程序仍然能够正确地执行,它仍然支持现有的JScript代码。
2.1.2 为什么选择VB.NET
本书选择VB.NET作为程序设计语言的原因是:首先,VB.NET是ASP.NET的默认编程语言;其次,VB.NET对于初学者来说十分简单易学,并且使用它可以完成C#和JScript.NET所能够完成的所有功能。
2.2 变量、常量和表达式
2.2.1 数据类型
VB.NET中有12种不同的数据类型,可以分成三类:数值类型、文本类型和混合类型。
数值类型是VB.NET数据类型的主要类型,共7种。数值类型的数据类型见表2-1。
表2-1 数值类型的数据类型
用于存放文本的数据类型有两个。文本类型的数据类型见表2-2。
表2-2 文本类型的数据类型
其中需要说明的是:
(1) 对于String类型,可以存放任何形式的字符串,它可以是纯粹的文本,也可以是文本和数字的组合或者是数字、日期等。例如"This is a book. "和"12345"都是字符串。对于字符串类型的数据,可以进行相关的字符串操作,例如连接、截断等。
(2) 对于Char类型,可以存储的只是一个字符,注意,这个字符的存储编码必需是一个数字。在计算机系统中,可以显示很多符号(不仅仅是英文字母),为了能够正确地显示,国际上有通用的标准(例如Unicode编码),为每个字符设定了一个标准的数值来表示这个字符。
其余的数据类型还有:Date数据类型、布尔数据类型和Object数据类型,其说明见表2-3。
表2-3 其他数据类型
其中需要说明的是:在VB.NET中,对于Boolean类型的数据,当需要把布尔类型的值转换为数值类型的时候,会把True当成1来处理,把False当作0来处理。当需要把数值类型的值转换为布尔类型的时候,会把0转换为False,而把其他的非0数值转换为True。
2.2.2 变量
变量用来存储程序中需要处理的数据,用户可以把变量看作是在内存中存储数据的盒子。在其他程序设计语言中,几乎都要求程序设计人员在使用变量之前定义变量的数据类型,因为不同数据类型的变量所需要的内存空间是不一样的:比如,字节型变量需要8位的空间,短整型变量需要16位空间等,这就表示盒子的容量是不一样的,所以为一种数据类型定义的变量就不能存放另一种数据类型的值。
在Visual Basic.NET中,创建变量的方式有两种:一种方法是使用Dim关键字,这是显式定义的方法。还可以使用隐式定义的方法,也就是在用户需要使用一个变量的时候直接写出这个变量并为它赋值。
显式定义方法如下所示:
Dim x
通过这样一条语句,就创建了一个名为x的变量。也可以用下面的方法一次定义多个变量: Dim a,x 这条语句创建了两个变量:a和x。 在这里,有以下几点需要说明: (1) 如何为变量取名字。Visual Basic.NET和其他语言一样,其变量名称必须以字母开头,只能包含字母、数字和下划线,并且不是Visual Basic.NET关键字。在为变量取名时,建议不要使用像a或者x这样的让人无法理解的变量名,而应该采用小写前缀加上有特定描述意义的名字的方式来为变量命名,这种命名方法被称为Hungarian法。变量名的前三个字母用于说明数据类型,第四个字母大写以表示变量的实际含义。例如下面的定义:
Dim strFileName
Dim intTotal
都可以说是定义了很好的变量名:用str和FileName两个部分组合来表示strFileName是用来存储字符串类型的文件名的,用int和Total两个部分组合来表示intTotal是用来存储整数类型的总和的。当然,对于程序员来说,这种命名约定并不是强制性的,仍然可以使用a和x这样的变量名,也可以用intTotal变量来存储一个字符串。但是很明显,如果用户都采用这种为变量命名的方式并在程序设计过程中遵循这样的好习惯,可以让程序易读,并减少出错的机会。
在VB.NET中,常用的约定前缀见表2-4。
表2-4 常用的变量命名约定 (2) 当使用Dim 语句的时候,可以在后面加上一个as关键字来指定一个变量的数据类型。例如:
Dim intTatal as Integer
这条语句表示创建一个名为intTatal的整数类型的变量,使用这种方法可以指明一个变量必须要保存什么类型的数据。虽然VB.NET并不强迫用户在定义变量的时候一定要指明其数据类型,但是建议用户在编写程序时使用这种方法来指明变量的数据类型,以减少程序出错的可能。
(3) 虽然可以使用隐式方法来创建变量,但是由于前面提到的原因,仍然建议使用显式的方法来定义变量。
(4) 在VB.NET中,是不区分大小写的,这就意味着,变量strFileName和变量strfilename将表示同一个变量。
2.2.3 运算符 在VB.NET中常用的运算符与其他的语言并没有什么不同。常用的运算符有:赋值运算符、算术运算符、字符串连接运算符、比较运算符和逻辑运算符。
-
赋值运算符 赋值运算符是最常用的运算符,它就是我们熟悉的等号(=)。需要注意的是,虽然它表面上是一个等号,但它并不是一个数学意义上的等号,它的意思是把等号后边的值赋值给等号前面的变量。
例如,如果定义了一个整数型变量intNumber,就可以使用下面的语句:
Dim intNumber as Integer
intNumber=1
intNumber=intNumber*3
可以看出,Do/Loop的执行和While/End While的执行没有太大的区别。用户也可以把上面例子中第4行中的Until改为While并相应地改变后面的条件来实现相同的功能。
-
For/Each 在某些特殊情况下,可以使用For/Each来实现对一个数组或集合(集合将在后面的章节中讲解)中元素的遍历。
For/Each语句的写法如下:
For Each item In Array or Collection
[statements]
Next
例2.10(02-10.aspx)用For/Each显示一个数组中的所有数据。
1: <%
2: Dim arrData(3)
3: Dim stritem as string
4: arrData(0)=“Beijing”
5: arrData(1)=“Shanghai”
6: arrData(2)=“Guangzhou”
7: For Each stritem In arrData
8: Response.Write (stritem & “ ”)
9: Next
10: %>
可以看出,For/Each循环与For/Next循环的区别是:在For/Next循环中需要指明循环的次数,而在For/Each循环中不需要这样就可以遍历到一个数组或集合的所有内容。另外需要说明的是,这种循环通常在集合中使用。
2.5 过程和函数 在程序设计过程中,随着代码量的不断增加,会出现很多地方使用同样代码的情况。为了能够减少同样代码的编写,ASP.NET允许使用一些小的程序将重复的代码只写一次,其他需要使用这段代码的地方调用这个小程序就可以了。
在ASP.NET中,实现这种小程序的方式有两种:过程和函数。
2.5.1 模块化的优点 模块化是在程序设计发展到一定程度的时候诞生的程序设计方法。在早期的程序设计过程中,由于机器的硬件配置低,所以程序的运行速度和效率十分重要,因此早期的程序设计人员会大量使用各种技巧保证程序的快速运行,而这些技巧导致的最直接后果就是程序的结构混乱,很难阅读。
随着机器硬件的不断更新,这些编程技巧所提高的程序运行速度已经微不足道,这时提高程序的可读性就变得十分重要,于是就出现了模块化程序设计方法。
模块化程序设计方法的特点是:在编写程序之前,把程序的功能分解成若干个小的任务,并把这些小任务看成是一个一个的模块。当各个模块编写完成之后,就可以把这些模块编译成为一个大型的程序。由于每个模块都有自己独立的功能,所以可以把这些模块分配给很多程序员来完成;而每个模块的功能都是详细定义的,所以可以建立完善的文档,使得程序的可读性大大提高。
2.5.2 过程和函数 VB.NET支持子过程和函数,它们都可以根据需要设置参数。它们之间惟一的区别是函数可以有返回值而子过程没有。
子过程的定义方式为:
Sub subname ([argument1[,…, argumentn]])
[statements]
End Sub
对于子过程的调用方式是直接调用过程名subname。如果有参数,就在后面按照次序将参数在括号中写好。
例2.11(02-11.aspx)用一个子过程显示对一个用户的问候信息:
1:
2: Sub SayHello(strUserName as String)
3: Response.Write (“Hello!” & strUserName & “ ”)
4: End Sub
5:
6: <%
7: SayHello(“Cindy”)
8: %>
在上面的例子中,有下面几点需要说明:
(1) 在第1行~第5行使用
(2) 在第2行~第4行定义了一个SayHello子过程。这个过程带有一个参数strUserName,并在第3行输出。
(3) 在第7行调用了这个子过程。在调用的时候,传入参数的值是“Cindy”。
函数的定义方式为:
Function functionname ([argument1[,…, argumentn]])
[statements]
[Return value]
[statements]
End Function
对于函数的调用方式是调用函数名functionname()。如果有参数,就按照次序写在括号中。
例2.12(02-12.aspx)用一个函数计算两个整数的和。
1:
2: Function Add(intData1 as Integer,intData2 as Integer) as Integer
3: intData1=intData1+intData2
4: Return intData1
5: End Function
6:
7: <%
8: Dim intTemp1,intTemp2 as Integer
9: intTemp1=2
10: intTemp2=3
11: Response.Write(Add(intTemp1,intTemp2))
12: Response.Write(" ")
13: Response.Write(intTemp1)
14: %>
在上面的程序中,有下面几点需要说明:
(1) 在第2行~第5行定义了一个函数Add。这个函数带有两个参数:intData1和intData2,并把一个整数作为返回值。
(2) 在第3行把参数intData1与intData2的和放到intData1中,并在第4行把intData1作为结果返回。
(3) 在第11行调用了这个函数,并把结果显示出来。
在上面的子过程和函数的讲解过程中,可以看出都可以采用带参数的方式来增加子过程和函数的灵活性。需要说明的是,参数的传递有两种方式:通过值传递参数和通过引用传递参数。
在调用子过程和函数的时候,如果没有明确地指出,所有的参数都是通过值进行传递的。所谓通过值进行传递,就是把参数的值复制到参数中。例如例2.12中第11行的Add(intTemp1,intTemp2),就是通过值进行传递的好例子。在真正执行第2行~第5行定义的Add函数时,是把intTemp1的值2复制给了intData1,把intTemp2的值3复制给了intData2。在第3行把intData1和intData2的和赋值给intData1的时候,intData1的值变成了5,但是这个时候,intTemp1的值仍然是2,不是5(通过第13行的执行可以看出来),这就是通过值传递参数。这时,intData1和intTemp1是两个不同的变量,在内存中占用不同的存储空间。
在函数和子过程中,使用关键字ByVal来显式表示通过值传递参数。也就是说,如果要用显式的方式进行定义,第2行的函数定义可以写成:
Function Add(ByVal intData1 as Integer, ByVal intData2 as Integer) as Integer
默认的情况是采用通过值传递参数。
那么什么是通过引用传递参数呢?请先看下面的例子。
例2.13(02-13.aspx)用一个函数计算两个整数的和。
1:
2: Function Add(ByRef intData1 as Integer,ByRef intData2 as Integer) as Integer
3: intData1=intData1+intData2
4: Return intData1
5: End Function
6:
7: <%
8: Dim intTemp1,intTemp2 as Integer
9: intTemp1=2
10: intTemp2=3
11: Response.Write(Add(intTemp1,intTemp2))
12: Response.Write(" ")
13: Response.Write(intTemp1)
14: %>
例2.13与例2.12的区别就在于第2行的Add函数的定义。在这里使用了ByRef关键字表示这时的参数是通过引用进行传递的。执行这个程序就会发现,在程序执行完之后,不但intData1的值变成了5,同时intTemp1的值也变成了5。
通过引用传递参数的方法是把参数的地址传递进去。在第11行进行传递的时候,不是把intTemp1的值复制给intData1,把intTemp2的值复制给intData2,而是把intTemp1的地址给了intData1的地址,把intTemp2的地址给了intData2的地址。在传递成功之后,intData1就是intTemp1,intData2就是intTemp2。所以在第3行intData1的值发生变化时,intTemp1的值也同时发生了变化。
2.5.3 变量的作用域 在进行变量声明时,变量声明的位置决定了这个变量的作用范围。在一个过程或函数外声明的变量是全局变量,对本程序内部所有的过程和函数都起作用;而在一个过程或函数内部声明的变量是局部变量,只对本过程或函数起作用。
下面通过一个例子说明全局变量和局部变量的区别。
例2.14(02-14.aspx)全局变量和局部变量的使用。
1:
2: Dim strGlobal as String=“global”
3: Sub SayHello
4: Dim strTemp as String=“hello!”
5: Response.Write (strTemp & “ ”)
6: Response.Write (strGlobal & “ ”)
7: if strGlobal<>"" then
8: Dim strTemp1 as String=“hello cindy!”
9: Response.Write (strTemp1 & “ ”)
10: end if
11: 'Response.Write (strTemp1 & “ ”)
12: End Sub
13:
14: <%
15: SayHello
16: %>
上面的例子中,有下面几点需要说明:
(1) 第2行声明的变量strGlobal定义在所有的函数或者过程之外,所以是一个全局变量。由于在定义这个变量的时候就为这个变量赋值为“global”,所以,在后面的程序中,第一次使用这个变量时这个变量的值就是“global”。
(2) 第3行~第12行定义了一个子过程SayHello。在这个过程中,首先在第4行定义了一个变量strTemp,由于这个变量是定义在子过程中的,所以这个变量是一个局部变量。在第5行显示这个变量的值的时候,会显示一个“hello!”字符串。
(3) 第6行要显示strGlobal的值,由于这是一个全局变量,所以会显示第1行赋值的“global”。
(4) 第7行~第10行定义了一个If/Endif代码块,在这个代码块中,定义了一个块级局部变量strTemp1(第8行)。由于这个变量是定义在代码块中的,所以只在这个代码块中起作用。所以在第9行要显示它的值的时候,会显示“hello cindy!”。而如果取消第11行的注释,系统将会通告strTemp1变量没有定义。
通过上面的例子可以看出,在编写程序的时候,要时刻注意变量的作用域的问题。因为在不同模块中修改全局变量会导致模块之间相互影响,违反了进行模块化程序设计的初衷。所以要设计好的程序,就应该尽量减少全局变量的使用。