==== ==== ==== ==== ==== ==== ==== ====
.
■ Visual Basic 编程标准 笔记.doc
.
○ Taylor 2008-1-30
.
==== ==== ==== ==== ==== ==== ==== ====
.
目录
译者序
前言
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第一部分 设 计
.
==== ==== ==== ==== ==== ==== ==== ====
■ 第1章 创建对象和工程模板 1
.
◆ 1.1 使用对象模板 1
.
◆ 1.2 使用项目模板 2
.
◆ 1.2.1 Visual Basic项目模板概述 2
.
◆ 1.2.2 创建自定义项目模板 4
.
注意 由于每个模块(包括窗体模块)都应该具备完整的错误跟踪手段(正如我在第6章中介绍的那样),所以应该将相应的错误处理特性添加给每个对象模板。它的目的是使每个对象模板尽量做到完整。每当基于常用模板的对象被添加给项目时,如果这些对象必须完成相同的工作,那么这项工作应该在模板文件本身中完成。
.
◆ 1.3 自定义模板的行为特性 4
.
◆ 1.3.1 激活模板和取消模板的激活状态 4
.
◆ 1.3.2 设置模板文件夹 5
.
使用对象和项目模板的主要目的是:
○ 促进和鼓励代码的复用
○ 缩短新项目和现有项目的开发时间
.
◆ 1.4 编程原则 5
.
◆ 1.4.1 不要将对象模板中的特定应用程序的值或特定组件的值进行硬编码 5
.
注意在对象模板中用常量取代硬编码的“幻数”,这个问题很重要,这样开发人员就能更容易理解和替换各个值。
.
1) 不要将对象模板中的路径进行硬编码。
2) 不要将对象模板中的应用程序名进行硬编码。
3) 不要将对象模板中的版本号进行硬编码。
4) 展示模板对象的属性,以便接受来自主应用程序的数据。不要展示公用变量或使用全局变量,而应该使用Property过程。如果使用Property过程,那么当值变更时,就能进行数据验证并执行代码。
.
◆ 1.4.2 在对象模板中提供内容广泛的注释,尤其是在需要进行修改的地方要加上注释 7
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第2章 设计模块和过程 9
.
◆ 2.1 创建具有很强内聚力的模块 9
.
◆ 2.2 创建松散连接和高度专用的过程 10
.
◆ 2.2.1 使所有过程都执行专门的任务 10
.
当你感到有问题时,请让别人审查你的代码,这通常有助于获得新的看法。
.
◆ 2.2.2 尽量使过程成为自成一体的独立过程 11
.
创建专用过程时,请考虑下列指导原则:
○ 将复杂进程放入专用过程。如果应用程序使用复杂的数学公式,请考虑将每个公式放入它自己的过程中。这样,使用这些公式的其他过程就不必包含用于该公式的实际代码。这样也可以更容易发现与公式相关的问题。
○ 将数据输入/输出(I/O)放入专用过程。在以后你可能需要改变数据输入/输出的处理方法。例如,可能要修改使用文本文件的应用程序,使它能够使用Microsoft Jet之类的数据库引擎。如果该应用程序的数据输入/输出代码在专用过程中被隔离,就可以更容易进行必要的修改。
○ 将专用过程中可能要修改的代码区隔离。如果你知道某个进程经常变更,请将这个多变的代码放入专用过程,以便以后可以更加容易地进行修改,并且减少无意中给其他进程带来问题的可能性。
○ 将业务规则封装在专用进程中。业务规则常常属于要修改的代码类别,应该与应用程序的其余部分隔开。其他过程不应该知道业务规则,只有要调用的过程才使用这些规则。
.
◆ 2.2.3 尽量减少扇入和扇出 12
.
◆ 2.2.4 设法按字母顺序对模块中的过程进行排序 12
.
设计模块和过程时,要达到下列目的:
○ 创建更加容易调试和维护的过程
○ 创建具有强大内聚力的模块
○ 创建高度专用的过程
○ 创建松散连接的过程
○ 尽量使过程具有独立性
○ 提高过程的扇入性
○ 降低过程的扇出性
.
◆ 2.3 编程原则 13
.
◆ 2.3.1 为过程和模块赋予表义性强的名字 13
.
(1) 给过程命名时应该大小写字母混合使用。
(2) 定义过程名时不要使用缩写。
.
◆ 2.3.2 为每个过程赋予单个退出点 15
.
解决这个问题的办法是在每个过程中创建一个PROC_EXIT标注。在这个标注下面,放入所有必要的清除代码和一个相应的Exit语句(Exit Sub、Exit Function和Exit Property)。每当你需要退出该过程时,只需加上一个GoTo PROC_Exit语句,而不必直接调用Exit命令。
.
创建单个退出点,可使过程更像是黑箱。代码的执行从一个门进来,代码的退出则从另一个门出去,因此产生的错误比较少,调试也不太难。创建单个退出点的操作是非常复杂的,但是它的好处是极大的。得到的好处大于你付出的努力,这种情况并不是总能碰到,因此务必充分利用它。
.
创建健壮的退出代码。当你将清除代码添加给过程时,决不要固步自封。如果正确的退出进程取决于某些变量的状态,请检查这些变量的值,并对清除代码作出相应的应答。
.
◆ 2.3.3 为每个过程赋予明确定义的作用域 18
.
作用域是指工程中的变量或过程的可视性。过程可以定义为拥有模块级作用域、全局作用域或友元作用域。
.
Visual Basic使用Public作为默认作用域。
.
◆ 2.3.4 用参数在过程之间传递数据 18
.
(1) 为每个参数指定数据类型。
(2) 根据情况传递数据ByVal或ByRef。除非另有说明,否则Visual Basic均按引用将数据传递给过程的参数。当变量按引用(ByRef)传递给过程的参数时,该过程就会收到一个原始变量的指针。对参数进行的后续修改均是对原始变量的修改。另外,当变量按值(ByVal)传递给参数时,该过程就会收到变量的一个拷贝(字符串变量是这条规则的例外)。对参数所做的任何修改只是对拷贝的修改,而原始变量将保持不变。可以使用的一个标准是在每个参数前面冠以ByRef或ByVal。这样,你就可以明确说明使用哪个进程,并且代码会变得更加直观明了。但是,给每个参数冠以ByRef或ByVal所需要的规则是非常重要的。
★ 笔记:字符串变量按值(ByVal)传递给参数时,值改不了。
(3) 始终要对数进行检验,决不要假设你的数据没有问题。
(4) 当参数只接受较小的一组值时,请使用枚举值。第4章将详细介绍枚举值的问题,不过这里也可以简单作一说明。如果参数只接受较小的一组值,可以为该参数创建一个枚举。使用枚举值,可以降低编码时出现数据输入错误的可能性。不过请记住,将参数说明为枚举型数据并不能保证传递给参数的值是枚举值的成员,你仍然必须检验该数据。枚举是非常有用的,并且有许多优点,只要有可能,就可以考虑使用枚举值。
★ 笔记:枚举型数据变量完全对应不上时,编译可通过,可生成Exe文件,只是运行时出错。
.
◆ 2.3.5 使用统一和直观明了的方式来调用过程 21
.
为了使代码尽可能直观明了,必须将调用Sub过程与调用Function过程区分开来。调用Sub过程时,始终都应使用关键字Call;调用Function过程时,始终都应检索Function调用的值,即使你并不使用这个值,也应这么做。
.
(1)调用Sub过程时始终都要使用Call关键字。
(2) 当你将变量设置为一个函数的结果时,请给调用的Function加上括号,即使它不带任何变元,也应该加上。
(3) 始终都应该检索函数的返回值,即使你并不使用它,也应该检索。
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第二部分 编程中使用的约定
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第3章 命名约定 23
.
◆ 3.1 数据类型后缀 23
.
你能知道%、&、!和#等后缀对应的是什么数据类型吗?它们分别是指Integer(整型数)、Long(长整型数)、Single(单精度实数)和Doable(双精度实数)。要记住这些后缀非常困难,因此人们不喜欢使用这种约定。
.
◆ 3.2 匈牙利标记法 23
.
◆ 3.2.1 表示变量数据类型的前缀 24
.
表 3-1 用作变量数据类型的前缀
数据类型 前缀
Boolean(布尔值) bln
Currency(货币) cur
Control(控件) ctr
Double(双精度实数) dbl
ErrObject(错误对象) err
Single(单精度实数) sng
Handle(句柄) hwnd
Long(长整型数) lng
Object(对象) obj
Integer(整型数)int
String(字符串) str
Use-defined type(用户定义的类型)udt
Variant(including Dates)(变码(包括日期)) vnt
Array(数组) a
.
当用户定义UDT时,它应该加上前缀type_。
.
如果使用Microsoft Windows API(应用程序编程界面),那么你会发现Windows API的类型并不将前缀用于成员变量。
.
◆ 3.2.2 表示变量的作用域的前缀 25
.
表 3-2 用作变量作用域的前缀
前缀 描述 举例
g 全局变量 g_strSavePath
m 模块或窗体的局部变量 m_blnDataChanged
st 静态变量 st_blnInHere
(无前缀) 过程的非静态局部变量 intIndex
.
◆ 3.2.3 其他前缀 26
.
表 3-3 用于标准控件的前缀
复选框 chk
线条 lin
组合框 cbo
列表框 lst
命令按钮 cmd
MDI子窗体 mdi
数据 dat
菜单 mun
目录列表框 dir
OLE容器 ole
驱动器列表框 drv
选项按钮 opt
文件列表框 fil
面板 pnl
图文框 fra
图片框 pic
窗体 frm
剪贴图 clp
组按钮 gpb
形状 shp
水平滚动条 hsb
文本框 txt
图象 img
计时器 tmr
标注 lbl
垂直滚动条 vsb
.
表 3-4 用于ActiveX控件的前缀
常用对话框 dlg
通信 com
与数据关联的组合框 dbc
网格 grd
与数据关联的网格 dbg
与数据关联的列表框 dbl
列表视图 Ivw
MAPI消息 mpm
MAPI会话 mps
MCI mci
大纲 out
报表 rpt
微调控件 spn
树状视图 tre
.
表 3-5 用于数据库对象的前缀
数据库 db
域(对象或对象集合) fld
索引(对象或对象集合) idx
查询定义 qry
记录集 rst
报表 rpt
表格定义 tbl
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第4章 使用常量和枚举值 28
.
硬编码的数字通常称为“幻数”,因为它们往往处于一种神秘的气氛之中。
.
◆ 4.1 使用常量 28
.
◆ 4.1.1 幻数很容易在数据输入时出错 28
.
◆ 4.1.2 幻数很难更新 28
.
◆ 4.1.3 常量使代码更容易阅读 29
.
关于常量,最后要说明的一点是,非常适合为常量赋予较宽的作用域,这与使用变量时的情况不同。
.
◆ 4.2 使用枚举值 29
.
◆ 4.2.1 创建自定义的枚举值 30
.
枚举值的所有成员都是长整型数,你不得使用其他数据类型。
.
◆ 4.2.2 使用自定义枚举值 30
.
请注意,简单地将参数说明为枚举类型,并不能保证传递给参数的值成为已定义的枚举成员之一。实际上这是枚举类型最常见的错误概念之一。
.
使用常量和枚值的目的是:
○ 减少数字换位和键入错误带来的代码错误
○ 将来可以更容易更改各个值
○ 使代码更加容易阅读
○ 确保向前兼容
.
◆ 4.3 编程原则 31
.
◆ 4.3.1 给所有常量加上前缀c_和作用域指示符 31
.
常量不同于变量的另一个标识特征是不使用数据类型前缀。
.
可以为常量规定一个数据类型,但是这增加了代码的复杂性,我不知道这样做是否有很好的道理。如果你一定要这样去做,应该使用第3章所说的变量命名前缀。
.
注意 如果不用Public关键字对常量进行显式说明,那么该常量将默认说明为Private常量。
.
如果不清楚常量是在何处说明的,你只需将光标置于常量名中的任何一个位置,并按下Shift + F2键。这时Visual Basic就会立即显示该常量的说明。
.
(1) 混合使用大小写字母来说明常量,并给每个常量加上前缀c_。请记住,全部使用大写字母来标识常量的做法已经过时了。
(2) 使用作用域指示符前缀来表示常量的作用域。了解常量的作用域对于代码的调试是非常重要的。在任何类型的模块中的Declarations部分中说明的所有常量都需要一个g或m指示符。
.
◆ 4.3.2 无论什么作用域,均用常量取代幻数 33
.
◆ 4.3.3 只要可能,均应使用枚举 33
.
◆ 4.3.4 引用控件数组的元素时请使用常量 34
.
◆ 4.3.5 将应用程序前缀或公司特定的前缀用于枚举成员 35
.
◆ 4.3.6 当枚举值不能使用时,使用常量 36
.
◆ 4.3.7 当参数接受有限数量的值时,请使用枚举 38
.
◆ 4.3.8 验证作为枚举类型传递的值 38
.
(1) 始终应该通过与有名成员而不是与幻数进行比较来验证数据。
(2) 使用Select Case来验证一个值是一组离散值的一个有效成员。
.
★ 笔记:枚举变量的枚举值成员应只加不减,不适用的应每次检验一下,保持向下兼容。
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第5章 变量 41
.
正确地说明变量并且使用始终一致的变量命名规则的目的如下:
○ 使每个变量的作用一目了然
○ 使每个变量的数据类型和作用域一目了然
○ 使代码中的各个进程更容易理解
○ 使代码的调试更加容易
○ 使变量的存储和处理更加有效
.
◆ 5.1 编程原则 41
.
◆ 5.1.1 定义有焦点的变量 41
.
创建和使用变量时,应该设法使每个变量服务于一个定义明确的目的。人们希望变量能够服务于双重目的,但是它带来的节省少量内存的好处往往被代码的复杂性所抵消。用于多个目的的变量称为无焦点的变量。如果需要对变量执行不相关的操作或计算,最好使用两个有焦点的变量,而不使用单个无焦点变量。阅读和调试包含无焦点变量的代码是非常困难的,这种代码本身更可能包含一些错误。
.
★ 笔记:其实也应避免多用途的过程和函数。
.
◆ 5.1.2 为变量赋予表义性强的名字 43
.
为变量选择什么样的名字,这是非常重要的。即使你的代码永远不被其他人查看,也应该将它编写成可供几十个其他编程人员查看的样子。
.
避免给变量命名为Temp。
.
◆ 5.1.3 在变量名中混合使用大小写字母 46
.
◆ 5.1.4 只对常用变量名和长变量名进行缩写 46
.
◆ 5.1.5 使用统一的量词 47
.
表 5-1 常用的变量量词
量词 说明
First 一组变量中的第一个变量
Last 一组变量中的最后一个变量
Next 一组变量中的下一个变量
Prev 一组变量中的上一个变量
Cur 一组变量中的当前变量
Min 一组变量中的最小值
Max 一组变量中的最大值
Save 保存必须在以后清除的另一个变量
Tmp 一个“暂时性”变量,其作用域在代码中是非常局限的。Temp变量的值通常只在单个过程中的一组相邻语句中有效
Scr 源代码。常用于比较和转换例程中
Dst 目的代码。常常与Src配合使用
.
◆ 5.1.6 使用肯定形式的布尔变量 47
.
使用否定形式的布尔变量会增加变量处理出错的机会,尤其是在复杂表达式中,更容易发生程序运行的错误。
.
◆ 5.1.7 显式说明变量 49
.
安装Visual Basic后,首先要做的事情之一就是激活这个特性。
.
◆ 5.1.8 用精心选择的数据类型说明变量 51
.
表 5-2 Visual Basic的数据类型
数据类型 取值范围
Byte(字节) 0~255
Boolean(布尔) True或False
Integer(整型数) -32768~32767
Long(长整型数) -2147483648至2147483647
Single(单精度) 负值为-3.402823E38至-1.401298E-45正值为1.401298E-45至3.402823E38
Double(双精度) 负值为-1.79769313486232E308至-4.94065645841247E-324正值为4.94065645841247E-324至1.79769313486232E308
Currency(货币) -922337203685,477.5808至9223372036854775807
Date(日期) 100年1月1日至9999年12月31日
Object(对象) 任何对象引用
Variable-length String(可变长度字符串) 0至大约20亿个字符
Variant(变形) 数字:最大为Double范围的任何数字值 字符串:范围与可变长度字符串相同
.
下面是使用数据类型时应该遵循的规则:
○ 若要存储任何类型的文本,请使用String数据类型。这种数据类型可以包含任何有效的键盘字符,包括数字和非字母字符。
○ 如果只要存放True和False这两个值,请使用Boolean数据类型。
○ 若要存放不包含小数位、大于或等于-32768、小于或等于32767的数字,请使用Integer数据类型。
○ 若要存放不带小数位的数字,但是数字值大于或小于Integer数据类型允许的值,请使用Long数据类型。Long数字常常指Long Integer(长整型数),不过它们是使用关键字Long定义的。
○ 若要存放包含小数位的数字,请使用Single数据类型。除非你编写极其复杂的数学应用程序,需要极大的数字或者近似0的数字,否则,Single数据类型几乎适用于存放包含小数的所有值。如果需要存放的数字大于Single数据类型能够存放的数字,则请使用Double数据类型。
○ 若要存放美元金额,请使用Currency数据类型。该数据类型使用固定的4位小数。不过,除非指定显示4位小数的值,否则当你显示该值时,它只显示两位小数。
○ 若要存放日期或时间值,请使用Date数据类型。使用这个数据类型时,Visual Basic能够识别常用的日期和时间格式。例如,如果存放的值是7/22/1997,Visual Basic将不把它作为简单的文本字符串来处理,它知道这代表1997年7月22日。
.
◆ 5.1.9 只有在绝对必要时才使用Variant 数据类型 54
.
当Visual Basic遇到运算符+时,它就会确定,如果可能,它必须使用数字进行数学运算。
.
有时Visual Basic对类型严格的变量(说明为特定数据类型的变量)进行强制转换,但是它更喜欢对Variant进行强制转换。
.
当Visual Basic对String变量进行操作时,它将符号+视为并置运算符。但是符号+的默认运行特性是用于数学运算。
.
注意决不要将符号+用于字符串并置运算,应该使用“和”字符。
.
如果可能,每行只说明一个变量。
.
◆ 5.1.10 尽量缩小变量的作用域 56
.
发现自己说明了一个全局变量时,应该停下来寻找一种方法,以求在不使用全局变量的情况下获得相同的功能,通常能够找到更好的选择,不过也并非尽然。例如,如果一个模块级变量只用在一个过程中,应该使它成为该过程的静态局部变量。这样,另一个过程就不可能无意中修改该变量的内容。
.
◆ 5.1.11 使用“和”字符对字符串进行并置操作 58
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第6章 对错误的处理 60
.
★ 笔记:Ulli's VB Code Formatter V2.17.8 对Error对象的理解是错误的。
.
应该努力编写没有错误的代码,不过创建每个过程时也应该假设它可能出现错误。这意味着每个过程必须包含错误处理程序。
.
◆ 6.1 Visual Basic的编译选项 60
.
◆ 6.2 Err对象 61
.
当遇到On Error语句(比如On Error Resume Next),并且在使用Exit Sub、Exit Function或Exit Property语句退出一个过程后,Error对象的属性值就被清除。
.
◆ 6.3 错误处理程序的类型 62
.
你应该知道,代码错误会将过程中的错误处理程序的调用栈“提升”到堆栈中的较高位置(本章后面将详细介绍)。
.
可以在一个过程中创建多个错误处理程序,但每次只能激活一个错误处理程序。Visual Basic将最新的On Error语句中指明的处理程序视为已经激活的错误处理程序。切换一个过程中的不同位置上的错误处理程序,往往是很有好处的,理解各个错误处理程序如何运行,是利用这一功能的关键。
.
◆ 6.3.1 使用On Resume Next以忽略错误 62
.
◆ 6.3.2 使用On Error GoTo转移执行的代码流 64
.
行标注是个文本串,用于标识一个单行代码。行标注可以是任何字符的组合,它以一个字母开始,以冒号(:)结尾。
.
注意标注应该全部使用大写字母,使之更加醒目。另外,不应该将多个语句放在一个代码行上,这条规则也适用于标注,因为标注也被视为代码语句。当控制转移到标注上时,将从标注下面这行代码继续执行。
.
也可以执行下列操作:
○ 使用一个Exit Sub、Exit Function或Exit Property语句,迫使代码的执行退出该过程(请注意,你始终都应该使用单个退出点,而不是直接从错误处理程序来退出代码)。
○ 使用GoTo PROC_EXIT语句,强制代码的执行转到过程的单个退出点。
○ 使用Resume Next语句,强制代码从产生错误的语句的下一行继续执行。
○ 使用Resume语句,强制代码返回到产生错误的这一行并继续执行。
○ 使用Resume <line>语句,并使代码转移到特定的语句上执行。
.
使用GoTo PROC_EXIT与Exit Sub、Exit Function或Exit Property语句的组合,强制代码的执行退出该过程,这个方法是非常简单明了的。
.
若要使代码返回到产生错误的语句继续执行,请使用Resume语句。
.
◆ 6.3.3 错误处理程序与调用栈 68
.
有一个非常重要的问题你必须了解,那就是错误如何在调用栈中向上移动。为了理解这个问题,有两个术语是必须介绍的。一个术语是“已激活的错误处理程序”,指On Error语句中最近指定的错误处理程序。另一个术语是“活动的错误处理程序”,指正在处理错误的进程中的错误处理程序。请注意,可能存在这样一种情况,即错误处理程序已经被激活,但它不是活动的处理程序。一旦错误处理程序被激活,它将保持激活状态,直到另一个错误处理程序被激活,或者包含错误处理程序的过程超出其作用域为止。当包含错误处理程序的过程超出其作用域时,便返回调用过程继续执行,同时上次被激活的错误处理程序再次被激活。
.
这个概念也适用于多个嵌套的过程。如果在一个过程中出现错误,而该过程并没有已激活的错误处理程序,那么就要检查调用带有错误的过程的那个过程,以便找出已经激活但并不是活动的错误处理程序。这个检查将在调用栈中连续向上进行,直到找出一个已激活但并不是活动的错误处理程序,或者到达调用栈的顶部。如果到达了调用栈的顶部,该错误即被视为未捕获的错误。如果遇到一个已被激活但不是活动的错误处理程序,便执行该错误,然后在包含该处理程序的过程中继续执行。
.
◆ 6.3.4 使用On Error GoTo 0,在运行时取消错误处理程序的激活状态 69
.
注意On Error GoTo 0只能使当前过程中的错误处理程序取消激活状态。如果On Error GoTo 0语句后面遇到了一个错误,该错误将在调用栈中向上传递,就象该过程中根本没有错误处理程序一样。如果在调用栈中的较高位置上找到一个已激活但不是活动的错误处理程序,那么该错误处理程序便负责处理该错误。
.
◆ 6.3.5 用调试方式激活错误处理程序和取消其激活状态 70
.
可以将Error Tr a p p i n g属性设置为下列值中的一个:
○ Break On All Errors(在所有错误上中止)。
○ Break In Class Module(在类模块中中止)。
○ Break On Unhandled Errors(在未处理的错误上中止)。
Break On All Errors实际上可使所有错误处理程序均取消激活状态。当出现一个错误时,无论是否激活了处理程序,代码均在出错的语句上进入中止方式,同时Visual Basic显示一条出错消息。这使你能够在IDE进行测试时处理意料不到的错误。
调试ActiveX组件时,Break In Class Module设置值是最有用的。一般来说,调用ActiveX组件的方法的过程中的已激活错误处理程序,将负责处理ActiveX组件的过程中尚未处理的任何错误。Break In Class Module设置值规定,不在ActiveX组件中处理的错误,会使ActiveX项目在产生该错误的语句上进入中止方式。这将使不是在ActiveX组件中处理的错误无法在调用栈中向上传递到客户程序中的这个过程,从而使它能够非常容易地对ActiveX组件进行调试。
Break On Unhandled Error设置值能够非常接近地模仿错误在已编译程序中被处理的情况。被已激活的错误处理程序捕获的错误将由这些处理程序进行处理,并且只有未处理的错误才会使得该程序进入中止方式。
.
◆ 6.4 中央错误处理程序 71
.
★ 笔记:参见程序“ErrorHandle”。
.
运用错误处理程序要达到的目标是:
○ 防止你的程序崩溃。
○ 可能时恰当地纠正错误。
○ 发生错误时将情况通知用户,以便纠正错误。
.
◆ 6.5 编程原则 76
.
◆ 6.5.1 使用On Error GoTo语句捕获意料之外的错误 76
.
◆ 6.5.2 使用On Error Resume Next语句捕获预料之中的错误 77
.
比如使用SetFocus将光标移到没有完全加载的窗体中的一个控件上时出现的Error 5。
.
不过要注意,使用On Error Resume Next语句可能有一定的危险,因为它会使你注意不到运行期的错误。不要将这个语句当作万应灵药来使用,如果你估计不会出现错误,则不要用它。
.
◆ 6.5.3 创建统一的错误处理程序块 79
.
如果MsgBox语句不是第一个语句,Err对象可能被清除,并且MsgBox语句不会返回正确的错误号或错误描述。
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第三部分 代码结构
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第7章 代码的格式化 83
.
史蒂夫·麦克奈尔(Steve McConell)在《Code Complete》(1993年Microsoft公司出版社出版)一书中写道:“格式化的基本特点是,好的直观布局能够展示程序的逻辑结构。”这确实是一句至理名言。即使一个过程的算法非常出色,编写粗糙的代码也是不受欢迎的。格式化的作用并不只是使代码的外观更好一些,更重要的是使代码更容易阅读和更容易理解。当你对代码进行格式化时,你应该:
○ 使代码便于阅读和理解。代码的读者应能像阅读文档的句子和段落那样来理解代码流。
○ 减少为理解代码的结构而必须做的工作。由嵌套的循环(循环中包含循环)或If...Then语句块组成的复杂代码结构,如果不使用缩进和白空间,就很难理解。
○ 将代码分割成功能块和便于理解的代码段,就像文档中的段落一样。第一步是创建许多个专用过程而不是创建一个大过程,以便执行几十项任务,这就像是将一个大文档分割成许多章一样。对各个过程中的代码进行分割,与将逻辑变元分割成段落是一样的。
○ 不要强制读者进行假设。当引用对象的默认属性而不显式指明属性时(例如,Text1=“Shiny Object”,而不是Text1.Text=“Shiny Object”),就会迫使读者作出假设。
○ 尽量使代码的结构具有正确而清楚的格式。只需使用正确的缩进方式,就能使代码具有正确而清楚的格式。
.
◆ 7.1 编程原则 86
.
◆ 7.1.1 不要将多个语句放在同一行上 86
.
◆ 7.1.2 使用行接续符 87
.
(1) 一行上的字符不得超过90个。
(2) 不要对多行语句进行右对齐,始终要对空格后面的语句进行分割。
(3) 分割两个表达式之间的执行复杂表达式计算的语句。
.
◆ 7.1.3 缩进后续行 90
.
(1) 当你将变量设置为某个值时,所有后续行的缩进位置应该与第一行的变量值相同。如果将变量设置为一个复杂表达式的计算结果,那么在子表达式之间断行可能更好些。
(2) 当你分割一个很长的过程标题时,所有后续行均应缩进两个制表位(通常为6个字符)。另外,你也可以将第一行后面的所有行缩进到第一个参数的起始位置。这两种缩进方法都是可行的。请选择一种最适合你的方法,并始终一贯地使用之。
(3) 当你调用一个过程时,后续行缩进到第一个参数的开始处。被调用的过程的名字将在传递给它的各个参数中显得非常突出。当你对调用接受多个参数的很长的过程名字的语句进行分割时,缩进到第一个参数位置是不实际的。在这种情况下,应该缩进两个制表位。
(4) 当你将变量或属性设置为等于表达式的计算结果时,请从等号后面分割该语句,以确保该表达式尽可能放在同一行上。如果该语句包含多个表达式,最好像前面讲过的那样在两个表达式之间断开语句。
.
◆ 7.1.4 运用语句缩进来显示代码的组织结构 92
.
虽然Visual Basic允许你将制表位设定为任意数目的字符量,但是公认的标准是3个字符。
.
应该在下列情况下对语句进行缩进:
(1) 当使用End If时,在If语句后缩进。
(2) 在Else语句后缩进。
(3) 在Select Case语句后缩进。
(4) 在Case语句后缩进。
(5) 在Do语句后缩进。
(6) 已经用行接续符分割的语句的各个行要缩进。
(7) 在With语句后缩进。
(8) 在调用Recordset对象的Edit或AddNew方法后缩进。Update或ConcelUpdate方法的缩进层次应该与Edit或AddNew语句相同。
(9) 在调用BeginTrans方法后缩进。
(10) 对从属于行标注的代码进行缩进。
.
◆ 7.1.5 对模块的Declarations部分中的代码进行缩进,显示其从属关系 98
.
(1) 对所有用户定义的数据类型说明的主体进行缩进。
(2) 对所有枚举说明的主体进行缩进。
.
◆ 7.1.6 使用白空间将相关语句组合在一起 99
.
(1) 将空行插入到每个If...Then构造的前面和后面(尤其是If语句前的注释的前面)。
(2) 将空行插入到每个Select Case语句的前面和后面。
(3) 将空行插入到每个循环的前面和后面。
(4) 在说明变量块的后面插入一个空行。
(5) 在执行统一任务的各个语句组之间插入一个空行。
(6) 在两个过程之间插入两个空行。
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第8章 代码的注释 106
.
使用代码注释时,应该达到下列目的:
○ 用文字说明代码的作用(即为什么要编写该代码,而不是如何编写)。
○ 明确指出该代码的编写思路和逻辑方法。
○ 使人们注意到代码中的重要转折点。
○ 使代码的阅读者不必在他们的头脑中仿真运行代码的执行过程。
.
◆ 8.1 编程原则 106
.
◆ 8.1.1 用文字说明代码的作用 106
.
注意 注释应该描述为什么要编写该代码段,而不是说明它如何起到该作用所用的方法,要说明为什么,而不是说明如何。
.
◆ 8.1.2 如果你想违背好的编程原则,请说明为什么 107
.
◆ 8.1.3 用注释来说明何时可能出错和为什么出错 108
.
原因是,如果窗体或父控件本身的图形尚未完全画好,那么SetFocus就可能运行失败,并报出Error 5。
.
◆ 8.1.4 在编写代码前进行注释 109
.
◆ 8.1.5 纯色字符注释行只用于主要注释 110
.
◆ 8.1.6 避免形成注释框 112
.
◆ 8.1.7 使用撇号来指明注释 112
.
◆ 8.1.8 增强注释的可读性 114
.
(1) 使用完整的语句。
(2) 避免使用缩写。
(3) 将整个单词大写,以突出它们的重要性。
.
◆ 8.1.9 对注释进行缩进,使之与后随的语句对齐 115
.
◆ 8.1.10 为每个过程赋予一个注释标头 115
.
◆ 8.1.11 使用内部注释来说明代码进程 118
.
(1) 请在每个If语句的前面加上注释。
(2) 在每个Select Case语句前面加上注释。
(3) 在每个循环(包括For...Next循环和Do循环)的前面加上注释。
(4) 在修改了全局变量的每个语句前面加上注释。
.
◆ 8.1.12 用行尾注释来说明变量 122
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第9章 循环结构 123
.
循环结构非常适合于:
○ 减少重复代码。
○ 迭代执行数组或集合。
○ 提高代码的运行速度和效率。
.
◆ 9.1 编码指导原则 123
.
◆ 9.1.1 使用For...Next,使代码循环运行规定的次数 123
.
(1) 递增量(Step)应该尽量使用常量。
(2) 循环结束后不要引用计数器变量。
(3) 所有Next语句均应包含计数器变量。
(4) 为了清楚起见,应该对For...Next循环中的代码主体语句进行缩进。
(5) 如果你必须提早退出For...Next循环,请使用Exit For语句。
.
◆ 9.1.2 使用Do...loop,使循环按照未定次数来运行 130
.
(1) 除非你有理由使用别的操作方法,否则请在循环的开始处计算Do循环的退出条件。
(2) 当你在While与Until之间进行选择时,请使用能实现最简单的条件的这个关键字。
(3) 尽可能使用Do循环或For...Next循环,而不要使用GoTo和一个标注。
.
◆ 9.1.3 用Do...Loop取代While...Wend 135
.
◆ 9.1.4 使用For Each...Next,循环运行一个集合的所有成员 135
.
将For Each...Next循环用于对象集合的许多编程员并不知道它也可以用于数组,这是幸运的,因为将For Each...Next用于数组会导致代码运行速度明显降低。
.
(1) 不要用For Each...Next来循环运行数据。
(2) 在For Each...Next循环中尽可能使用特定的数据类型。
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第10章 控制代码流 140
.
控制代码流时,要达到的目的是
○ 在规定的情况下使用正确的判断构造;
○ 降低代码的复杂性,使之更容易阅读和调试;
○ 最大限度地减少表达式计算中出错的机会;
.
◆ 10.1 编程原则 140
.
◆ 10.1.1 当根据一个条件是True还是False来作出判断时,使用If...Then...Else 140
.
(1) 即使只有一个语句被执行,也应考虑使用End If构造。
(2) 不要认为Visual Basic会使复合条件短路。
.
◆ 10.1.2 对非布尔表达式与各种可能的值进行比较时,使用Select Case 语句 143
.
(1) 即使不需要,也应该在每个Select Case构造中包含Case Else语句。
(2) 所有Case语句都应该使用便于理解的顺序。
但是大多数情况下,速度问题的重要性低于代码的可读性和维护的简便性。在这种情况下,请按字母或数字顺序的项目排序,这样,代码的调试以及将新值添加给Case列表就比较容易。
(3) 不要编写决不会产生True结果的Case语句。
.
◆ 10.1.3 用行尾注释使嵌套式判断结构更加清楚 147
.
◆ 10.1.4 对表达式进行格式化,以便进行准确的计算和代码的理解 148
.
(1) 决不要将布尔表达式与True或False相比较。
(2) 创建的布尔变量名应该反映肯定的条件而不是否定的条件。
(3) 为了清楚起见,用括号将表达式括起来。
(4) 使代码流更加清楚。
.
◆ 10.1.5 尽可能不要使用GoSub 149
.
◆ 10.1.6 只有当没有其他替代方法或者当转移到一个错误处理程序或单个退出点时,才使用GoTo语句 150
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第四部分 用户界面的操作
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第11章 用户界面的设计 153
.
★ 笔记:
○《About Face: The Essentials of User Interface Design》
(IDG Books worldwide出版社1995年出版)
中文版,超星格式
○《Developing User Interfaces for Microsoft Windows》
(Microsoft出版社1999年出版)
英文版
○《The Windows Interface Guidelines for Software Design》
(Microsoft出版社1995年出版)
暂无
.
◆ 11.1 界面设计必须保持一致 153
.
界面设计的一致性要达的目的是:
○ 创建程序中统一的界面,并且创建不同应用程序中统一的界面;
○ 使得用户能够充分利用他们现有的技巧(即使用可复用的知识);
○ 减少用户在操作中的混乱和困难;
○ 形成醒目的界面,建立用户的信心,使用户感到满意。
.
◆ 11.2 编程原则 154
.
◆ 11.2.1 为窗体赋予统一的外观和行为特性 154
.
(1) 为每个窗体赋予相应的边框样式。
1) Fixed Dialog(固定对话框)。
2) None(无边框窗体)。
3) Fixed Single(固定单线窗体)。
4) Sizable(可缩放窗体)。
5) 固定工具窗口和可缩放工具窗口。
(2) 为每个窗体提供一个智能的和一致的起始位置。
(3) 正确卸载窗体,释放窗体占用的资源。
若要彻底卸载一个窗体,唯一的办法是将它设置为等于Nothing。
除非窗体专门指明要保留它的值,否则请在窗体的Unload事件中将窗体设置为等于Nothing。这样,你的代码将占用较少的资源,并且它会更加可靠和更加一致地运行(因为每次加载窗体时,就会创建窗体的“清洁”版本)。
(4) 不要创建变形窗体。
.
★ 笔记:参见程序“FormUnload”。
.
◆ 11.2.2 使控件具备标准外观 162
.
(1) 使文本框和其他“单行控件”的高度与标准组合框相同。
(2) 将标注放在和与其相一致的控件有关的正确的纵向位置上。
下面是使用标注控件时应该遵循的一些原则:
○ 除非你有特殊原因进行另外的设置,否则请将每个标注的Autosize(自动调整大小)设置为True。
○ 除非你有特殊原因进行另外的设置,否则请将每个标注的BackStyle(背景样式)设置为Transparent(透明)。
○ 将标注的Top(顶部)属性设置为比标准相关控件的Top属性大4个象素。这个值的设置可能不太方便,因为Visual Basic的对齐工具不能为你进行这项设置。但是,你的窗体将拥有更好和更加一致的外观。
○ 标注的文字应该以冒号(:)为结尾。
(3) 除非你有特定的理由进行另外的设置,否则请为所有标注控件赋予一个透明背景。
(4) 当控件不能使用时,请取消其激活状态,而不要将它们隐藏起来。
(5) (如果需要的话)酌情使用Tag(标记)属性。
.
◆ 11.2.3 在规定情况下使用最佳界面组件 167
.
(1) 用文本框控件显示可编辑文本。
(2) 用选项按钮来显示包含5个或少于5个项目的静态列表。
注意之所以使用For...Each循环,而不是使用For...Next循环,是因为控件数组可以在它们的序列中不带索引号。For...Each循环将对每个控件进行测试,而不管序列中是否存在任何间隔。
(3) 当不关心是否存在空格或者用户需要迅速查看许多值时,请使用列表框显示带有5个以上项目的动态列表和静态列表。
(4) 用组合框显示带有5个以上项目的动态列表和静态列表。
(5) 使用复选框,让用户能在小型静态列表中切换不同的选项。
(6) 只有在绝对必要时才选用图片框控件。
(7) 使用滚动条来指明数量和速度。
.
◆ 11.2.4 提供便于理解和使用的菜单 171
.
(1) 按照与其他流行的Windows应用程序相一致的方式,对菜单进行格式化和组织。
(2) 将快捷键赋予常用菜单项。
(3) 每个工具栏按钮应该有一个对应的菜单项。
.
◆ 11.2.5 尽可能使用系统颜色 177
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第12章 用户的输入和通知消息 179
.
◆ 12.1 用户的输入 179
.
◆ 12.2 通知消息 180
.
处理用户的输入和通知消息时,要达到的目的包括:
○ 为尽可能多的函数建立交互式二重性;
○ 支持充分的键盘导航;
○ 了解你的用户并预测他们使用你的程序时所采用的方法;
○ 用简明扼要的专业性语言告诉用户他们必须知道的消息。
.
◆ 12.3 编程原则 180
.
◆ 12.3.1 确保完善的键盘导航和交互操作特性 180
.
(1) 精心设置所有窗体的Tab键顺序。
(2) 方便时创建对话框中的默认命令按钮和Cancel(取消)命令按钮。
(3) 将组合键赋予常用命令按钮。
○ 不要将组合键赋予Default或Cancel属性设置为True的命令按钮。
○ 赋予的组合键不要与菜单项的组合键发生冲突。
(4) 设置与数据域相关联的控件的MaxLength属性。
.
◆ 12.3.2 提供统一和直观的鼠标交互操作特性 185
.
(1) 只要有可能,就应提供弹出式菜单。
(2) 用鼠标指针为用户提供反馈信息。
(3) 当显示弹出式菜单以便对选定的列表项目进行操作时,始终要在显示弹出式菜单之前选定被点击的项目。虽然鼠标右键可以用来显示弹出式菜单,但是列表框控件并不承认右单击是选定项目的方法。使用对列表框控件中的指定项目进行操作的命令来打开弹出式菜单时,你必须编写代码以便确保鼠标右键点击的项目是菜单出现时被选定的项目。这最好用MouseDown事件来实现。
.
◆ 12.3.3 创建有创意和功能良好的消息框 193
.
(1) 为既定情况创建适当类型的消息框。
(2) 提供真正有意义的按钮。
若要为buttons参数设定多个常量,请使用Or。
(3) 要对所有的消息进行校对。
(4) 消息框中不要使用技术性术语。
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第五部分 小组操作的项目
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第13章 版本控制 199
.
版本控制要达到的目的包括:
○ 编译最新和最稳定的组件;
○ 给所有已编译的程序编制版本;
○ 维护版本中的修改的历史信息;
○ 对项目和其他源文件进行备份,防止造成工作损失和时间浪费。
.
◆ 13.1 编程原则 199
.
◆ 13.1.1 每次对程序编译后应将版本号递增1 199
.
◆ 13.1.2 在About对话框中显示程序的版本号 200
.
◆ 13.1.3 保持ActiveX组件中的向后兼容性 201
.
1. 撤消兼容性
2. 保持项目的兼容性
3. 保持全面兼容
◆ 13.1.4 在Readme文件中记下所做的修改 205
.
◆ 13.1.5 对文件做好备份 206
.
◆ 13.1.6 使用Microsoft Visual SourceSafe 来维护源代码的版本 206
.
==== ==== ==== ==== ==== ==== ==== ====
.
■ 第14章 源代码控制 207
.
◆ 14.1 小组软件开发必须解决的问题 207
.
◆ 14.2 了解Visual SourceSafe 208
.
◆ 14.3 安装Visual SourceSafe 208
.
◆ 14.3.1 创建Visual SourceSafe数据库 209
.
◆ 14.3.2 打开Visual SourceSafe数据库 210
.
◆ 14.3.3 将用户添加给Visual SourceSafe 数据库 211
.
◆ 14.3.4 将Visual Basic工程置于SourceSafe控件下 211
.
◆ 14.4 Visual Basic项目与Visual SourceSafe 213
.
◆ 14.4.1 指定工作文件夹 214
.
◆ 14.4.2 创建项目的工作拷贝 215
.
◆ 14.4.3 使用Visual SourceSafe Explorer 借出文件 216
.
◆ 14.4.4 通过Visual Basic IDE借出和归还文件 218
.
◆ 14.4.5 将新文件添加给源代码控制下的项目 219
.
◆ 14.4.6 获取文件的最新版本 219
.
◆ 14.4.7 对不同版本进行比较 221
.
==== ==== ==== ==== ==== ==== ==== ====
.