编写本标准的目的是为了统一软件编程风格,提高软件源程序的可读性、可靠性和可重用性,提高软件源程序的质量和可维护性,减少软件维护成本,最终提高软件产品生产力。
本规范分成规则性和建议性两种:对于规则性规范,要求所有软件开发人员严格执行;对于建议性规范,各项目编程人员可以根据实际情况选择执行。本规范的示例都以C#语言描述。
本规范的内容包括:基本原则、布局、注释、命名规则、声名、表达式与语句、类与接口等。规范最后给出了标准模版供软件人员参考。
自本标准实施之日起,以后新编写的和修改的代码均应执行本标准。
1 范围
本标准规定了C#语言的编程规范,主要包括基本原则、布局、注释、命名规则、声明、表达式与语句、类与接口等。
本标准适用于使用C#语言编码的所有软件。本规范自生效之日起,对以后新编写的和修改的代码有约束力。
2 术语和定义
下列术语和定义适用于本标准。
2.1 原则
编程时应该坚持的指导思想。
2.2 规则
编程时必须遵守的约定。
2.3 建议
编程时必须加以考虑的约定。
2.4 说明
对此规则或建议的必要的解释。
2.5 正例
对此规则或建议给出的正确例子。
2.6 反例
对此规则或建议给出的反面例子。
3 基本原则
【原则1-1】首先是为人编写程序,其次才是计算机。 |
说明:这是软件开发的基本要点,软件的生命周期贯穿产品的开发、测试、生产、用户使用、版本升级和后期维护等长期过程,只有易读、易维护的软件代码才具有生命力。
【原则1-2】保持代码的简明清晰,避免过分的编程技巧。 |
说明:简单是最美。保持代码的简单化是软件工程化的基本要求。不要过分追求技巧,否则会降低程序的可读性。
【原则1-3】所有的代码尽量遵循公共语言规范(CLS)。 |
说明:编程时以该规范为准,规范没有规定的内容参考上面的标准。
【原则1-4】编程时首先达到正确性,其次考虑效率。 |
说明:编程首先考虑的是满足正确性、健壮性、可维护性、可移植性等质量因素,最后才考虑程序的效率和资源占用。
【原则1-5】尽量避免使用GOTO语句。 |
【原则1-6】尽可能重用、修正老的代码。 |
说明:尽量选择可借用的代码,对其修改优化以达到自身要求。
【原则1-7】 尽量减少同样的错误出现的次数。 |
说明:事实上,我们无法做到完全消除错误,但通过不懈的努力,可以减少同样的错误出现的次数。
4 布局
程序布局的目的是显示出程序良好的逻辑结构,提高程序的准确性、连续性、可读性、可维护性。更重要的是,统一的程序布局和编程风格,有助于提高整个项目的开发质量,提高开发效率,降低开发成本。同时,对于普通程序员来说,养成良好的编程习惯有助于提高自己的编程水平,提高编程效率。因此,统一的、良好的程序布局和编程风格不仅仅是个人主观美学上的或是形式上的问题,而且会涉及到产品质量,涉及到个人编程能力的提高,必须要引起重视。
4.1 基本格式
【规则2-1-1】源代码文件(.cs)的布局顺序是:using语句、命名空间、注释、类。 |
说明:以下内容如果某些节不需要,可以忽略。但是其它节要保持该次序。
正例:
using System;
namespace ZTE.xxx
{
/// <summary>
/// 版权所有: 版权所有(C)
2004,中兴通讯
/// 内容摘要: 本类是…..,包括主要……模块、……函数及功能是…….
/// 完成日期: 输入完成日期,例:2004年3月1日
/// 版 本:
/// 作 者:
///
/// 修改记录1: 修改历史记录,包括修改日期、修改者及修改内容
/// 修改日期:
/// 版 本 号:
/// 修 改 人:
/// 修改内容:
/// 修改记录2: …
/// </summary>
public
class Sample
{
}
}
【规则2-1-2】遵循统一的布局顺序来书写using语句,不同类别的using语句之间用空行分隔。 |
说明:using命名空间语句的排列顺序为System开头的命名空间在最前面,接下来是引自外部的命名空间,再接下来是应用程序自身的命名空间,即using 中标准的命名空间要在本地的命名空间之前,而且按照字母顺序排列。
正例:
using System; //
.Net自身的
using
System.Data;
using FarPoint.Win.Spread; //第三方的
using ZTE.DSS.Public; //程序自身的
【规则2-1-3】程序中一行的代码和注释不能超过80列。 |
说明:包括空格在内不超过80列。
【规则2-1-4】if、else、else if、for、while、do等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加
{ }。 |
说明:这样可以防止书写失误,也易于阅读。
正例:
if (varible1 < varible2)
{
varible1 = varible2;
}
反例:下面的代码执行语句紧跟if的条件之后,而且没有加{},违反规则。
if (varible1 < varible2) varible1 = varible2;
〖建议2-1-4〗源程序中关系较为紧密的代码应尽可能相邻。 |
说明:这样便于程序阅读和查找。
正例:
iLength = 10;
iWidth = 5; // 矩形的长与宽关系较密切,放在一起。
StrCaption = “Test”;
反例:
iLength = 10;
strCaption = “Test”;
iWidth = 5;
4.2
对齐
【规则2-2-1】 禁止使用TAB键,必须使用空格进行缩进。缩进为4个空格。 |
说明:消除不同编辑器对TAB处理的差异,有的代码编辑器可以设置用空格代替TAB键。
【规则2-2-2】程序的分界符‘{’和‘}’应独占一行并且位于同一列,同时与引用它们的语句左对齐。{ }之内的代码块使用缩进规则对齐。 |
说明:这样使代码便于阅读,并且方便注释。
do while语句和结构的类型化时可以例外,while条件和结构名可与 } 在同一行。
正例:
void Function(int iVar)
{ // 独占一行并与引用语句左对齐。
while (condition)
{
DoSomething(); // 与{ }缩进4格
}
}
反例:
void Function(int iVar){
while (condition){
DoSomething();
}}
【规则2-2-3】相关的赋值语句等号对齐。 |
正例:
tPDBRes.wHead = 0;
tPDBRes.wTail = wMaxNumOfPDB - 1;
tPDBRes.wFree = wMaxNumOfPDB;
tPDBRes.wAddress = wPDBAddr;
tPDBRes.wSize = wPDBSize;
4.3
空行空格
【规则2-3-1】不同逻辑程序块之间要使用空行分隔。 |
说明:空行起着分隔程序段落的作用。适当的空行可以使程序的布局更加清晰。
正例:
void Hey(void)
{
[Hey实现代码]
}
// 空一行
void Ack(void)
{
[Ack实现代码]
}
反例:
void Hey(void)
{
[Hey实现代码]
}
void Ack(void)
{
[Ack实现代码]
}
// 两个函数的实现是两个逻辑程序块,应该用空行加以分隔。
【规则2-3-2】一元操作符如“!”、“~”、“++”、“--”、“*”、“&”等前后不加空格。“[]”、“.”这类操作符前后不加空格。 |
正例:
!bValue
~iValue
++iCount
&fSum
aiNumber[i] = 5;
tBox.dWidth
【规则2-3-3】多元运算符和它们的操作数之间至少需要一个空格。 |
正例:
fValue = fOldValue;
fTotal + fValue
iNumber += 2;
【规则2-3-4】关键字之后要留空格。 |
说明:if、for、while等关键字之后应留一个空格再跟左括号‘(’,以突出关键字。
【规则2-3-5】函数名之后不要留空格。 |
说明:函数名后紧跟左括号‘(’,以与关键字区别。
【规则2-3-6】‘(’向后紧跟,‘)’、‘,’、‘;’向前紧跟,紧跟处不留空格。‘,’之后要留空格。‘;’不是行结束符号时其后要留空格。 |
正例:
例子中的 凵 代表空格。
for凵(i凵=凵0;凵i凵<凵MAX_BSC_NUM;凵i++)
{
DoSomething(iWidth,凵iHeight);
}
【规则2-3-7】注释符与注释内容之间要用一个空格进行分隔。 |
正例:
/* 注释内容 */
// 注释内容
反例:
/*注释内容*/
//注释内容
4.4
断行
【规则2-4-1】长表达式(超过120列)要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐。 |
说明:条件表达式的续行在第一个条件处对齐。
for循环语句的续行在初始化条件语句处对齐。
函数调用和函数声明的续行在第一个参数处对齐。
赋值语句的续行应在赋值号处对齐。
正例:
if ((iFormat == CH_A_Format_M)
&& (iOfficeType == CH_BSC_M)) // 条件表达式的续行在第一个条件处对齐
{
DoSomething();
}
for (long_initialization_statement;
long_condiction_statement; // for循环语句续行在初始化条件语句处对齐
long_update_statement)
{
DoSomething();
}
// 函数声明的续行在第一个参数处对齐
BYTE ReportStatusCheckPara(BYTE ucCallNo,
BYTE ucStatusReportNo);
// 赋值语句的续行应在赋值号处对齐
fTotalBill = fTotalBill + faCustomerPurchases[iID]
+ fSalesTax(faCustomerPurchases[iID]);
【规则2-4-2】函数声明时,类型与名称不允许分行书写。 |
正例:
double CalcArea(double dWidth, double dHeight);
反例:
double
CalcArea(double dWidth, double dHeight);
5
注 释
注释有助于理解代码,有效的注释是指在代码的功能、意图层次上进行注释,提供有用、额外的信息,而不是代码表面意义的简单重复。
【规则3-1】类、方法、属性的注释采用XML文档格式注释。代码间多行注释为“/* … */”,单行注释采用“// …”。 |
正例:public class Sample
{
//数据成员 (单行注释)
private int m_iProperty1;
/// <summary> (XML注释)
/// 示例属性
/// </summary>
public
int Property1
{
get
{
return m_iProperty1;
}
/* set
( 多行注释)
{
m_iProperty1 = value;
}
*/
}
【规则3-2】一般情况下,源程序有效注释量必须在20%以上。 |
说明:注释的原则是有助于对程序的阅读理解,注释不宜太多也不能太少,注释语言必须准确、易懂、简洁。有效的注释是指在代码的功能、意图层次上进行注释,提供有用、额外的信息。
【规则3-3】注释使用中文。 |
说明:对于特殊要求的可以使用英文注释,如工具不支持中文或国际化版本时。
|
【规则3-4】类、接口头部应进行XML注释。 |
说明:注释必须列出:内容摘要、版本号、作者、完成日期、修改信息等。
正例:
/// <summary>
/// 版权所有: 版权所有(C)
2004,中兴通讯
/// 内容摘要:
本类的内容是…..
/// 完成日期:2004年3月1日
/// 版 本:V1.0
/// 作 者:小张
///
/// 修改记录1:
/// 修改日期:2004年3月10日
/// 版 本
号:V1.2
/// 修 改
人:小张
/// 修改内容:对方法……进行修改,修正故障BUG……。
/// 修改记录2:
/// 修改日期:2004年3月20日
/// 版 本
号:V1.3
/// 修 改
人:小张
/// 修改内容:对方法……进行进一步改进,修正故障……。
/// </summary>
|
【规则3-5】公共方法前面应进行XML注释,列出:函数的目的/功能、输入参数、返回值等。 |
|
【规则3-6】包含在{ }中代码块的结束处应加注释,便于阅读。特别是多分支、多重嵌套的条件语句或循环语句。 |
说明:此时注释可以用英文,方便查找对应的语句。
正例:
void Main()
{
if (…)
{
…
while (…)
{
…
} /* end of while (…) */ // 指明该条while语句结束
…
} /* end of if (…) */ // 指明是哪条语句结束
} /* end of void main()*/ // 指明函数的结束
【规则3-7】保证代码和注释的一致性。修改代码同时修改相应的注释,不再有用的注释要删除。 |
【规则3-8】注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。 |
说明:在使用缩写时或之前,应对缩写进行必要的说明。
正例:
如下书写比较结构清晰
/* 获得子系统索引 */
iSubSysIndex = aData[iIndex].iSysIndex;
/* 代码段1注释 */
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
反例1:
如下例子注释与描述的代码相隔太远。
/* 获得子系统索引 */
iSubSysIndex = aData[iIndex].iSysIndex;
反例2:
如下例子注释不应放在所描述的代码下面。
iSubSysIndex = aData[iIndex].iSysIndex;
/* 获得子系统索引 */
反例3:
如下例子,显得代码与注释过于紧凑。
/* 代码段1注释 */
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
【规则3-9】注释与所描述内容进行同样的缩排。 |
说明:可使程序排版整齐,并方便注释的阅读与理解。
正例:
如下注释结构比较清晰
int DoSomething(void)
{
/* 代码段1注释 */
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
}
反例:
如下例子,排版不整齐,阅读不方便;
int DoSomething(void)
{
/* 代码段1注释 */
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
}
【规则3-10】对分支语句(条件分支、循环语句等)必须编写注释。 |
说明:这些语句往往是程序实现某一特殊功能的关键,对于维护人员来说,良好的注释有助于更好的理解程序,有时甚至优于看设计文档。
〖建议3-1〗通过对函数或过程、变量、结构等正确的命名以及合理地组织代码结构,使代码成为自注释的。 |
说明:清晰准确的函数、变量命名,可增加代码的可读性,减少不必要的注释。
〖建议3-2〗尽量避免在注释中使用缩写,特别是不常用缩写。 |
说明:在使用缩写时,应对缩写进行必要的说明。
6 命名规则
好的命名规则能极大地增加可读性和可维护性。同时,对于一个有上百个人共同完成的大项目来说,统一命名约定也是一项必不可少的内容。本章对程序中的所有标识符(包括命名空间、变量名、常量名、控件名、参数名、属性名、方法名、类名、接口等)的命名做出约定。
【规则4-1】标识符要采用英文单词或其组合,便于记忆和阅读,切忌使用汉语拼音来命名。 |
说明:标识符应当直观且可以拼读,可望文知义,避免使人产生误解。程序中的英文单词一般不要太复杂,用词应当准确。
【规则4-2】标识符只能由26个英文字母,10个数字,及下划线的一个子集来组成,并严格禁止使用连续的下划线,下划线也不能出现在标识符头或结尾(预编译开关除外)。 |
说明:这样做的目的是为了使程序易读。因为 variable_name 和 variable__name 很难区分,下划线符号‘_’若出现在标识符头或结尾,容易与不带下划线‘_’的标识符混淆。
【规则4-3】标识符的命名应当符合“min-length && max-information”原则。 |
说明:较短的单词可通过去掉“元音”形成缩写,较长的单词可取单词的头几个字母形成缩写,一些单词有大家公认的缩写,常用单词的缩写必须统一。协议中的单词的缩写与协议保持一致。对于某个系统使用的专用缩写应该在某处做统一说明。
正例:如下单词的缩写能够被大家认可:
temp 可缩写为 tmp ;
flag 可缩写为 flg ;
statistic 可缩写为 stat ;
increment 可缩写为 inc ;
message 可缩写为 msg ;
规定的常用缩写如下:
常用词 |
缩写 |
Argument |
Arg |
Buffer |
Buf |
Clear |
Clr |
Clock |
Clk |
Compare |
Cmp |
Configuration |
Cfg |
Context |
Ctx |
Delay |
Dly |
Device |
Dev |
Disable |
Dis |
Display |
Disp |
Enable |
En |
Error |
Err |
Function |
Fnct |
Hexadecimal |
Hex |
High Priority Task |
HPT |
I/O System |
IOS |
Initialize |
Init |
Mailbox |
Mbox |
Manager |
Mgr |
Maximum |
Max |
Message |
Msg |
Minimum |
Min |
Multiplex |
Mux |
Operating System |
OS |
Overflow |
Ovf |
Parameter |
Param |
Pointer |
Ptr |
Previous |
Prev |
Priority |
Prio |
Read |
Rd |
Ready |
Rdy |
Register |
Reg |
Schedule |
Sched |
Semaphore |
Sem |
Stack |
Stk |
Synchronize |
Sync |
Timer |
Tmr |
Trigger |
Trig |
Write |
Wr |
【规则4-4】采用应用领域相关的术语来命名。 |
说明:软件开发人员应注意软件用户的一些约定术语,不应当随意的创造术语,这会降低软件的易用性。
【规则4-5】程序中不要出现仅靠大小写区分的相似的标识符。 |
【规则4-6】用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。 |
说明:下面是一些在软件中常用的反义词组。
add/remove ; begin/end ; create/destroy ; insert/delete ;
first/last ; get/release ; increment/decrement ; put/get ;
add/delete ; lock/unlock ; open/close ; min/max ;
old/new ; start/stop ; next/previous ; source/target ;
show/hide ; send/receive ;source/destination ; cut/paste ;
up/down
【规则4-7】常量名都要使用大写字母, 用下划线 ‘_’ 分割单词。 |
正例:如 DISP_BUF_SIZE、MIN_VALUE、MAX_VALUE 等等。
【规则4-8】一般变量名不得取单个字符(如i、j、k等)作为变量名,局部循环变量除外。 |
说明:变量,尤其是局部变量,如果用单个字符表示,很容易出错(如l误写成1),而编译时又检查不出,则有可能增加排错时间。过长的变量名会增加工作量,会使程序的逻辑流程变得模糊,给修改带来困难,所以应当选择精炼、意义明确的名字,才能简化程序语句,改善对程序功能的理解。
【规则4-9】使用一致的前缀来区分变量的作用域。 |
说明:变量活动范围前缀规范如下:
m_
: 类的成员变量(属性所对应的变量)
空 : 局部变量不加范围前缀
【规则4-10】使用一致的小写类型指示符作为前缀来区分变量的类型。 |
说明:常用变量类型前缀列表如下:
i : int
f : float
d : double
dcm :
decimall
ch : char
l : long
bt : byte
sbt : sbyte
b : bool
sht : short
usht : ushort
ul : ulong
ar : array
str : string
st : struct
以上前缀可以进一步组合,在进行组合时,数组类型的前缀指示符必须放在变量类型前缀的首位。
【规则4-11】完整的变量名应由前缀+变量名主体组成,变量名的主体应当使用“名词”或者“形容词+名词”,且首字母必须大写。 |
说明:各种前缀字符可能组合使用,在这种情况下,各前缀顺序为:变量作用域前缀、变量类型前缀。
【规则4-12】控件命名应采用完整的英文描述符命名,名字的前缀是控件类型名缩写。 |
说明:
控件 |
缩写 |
Label |
lbl |
TextBox |
txt |
CheckBox |
chk |
Button |
btn |
ListBox |
lst |
DropDownList |
ddlst |
等等 |
|
【规则4-13】参数名应由前缀+变量名主体组成,变量名的主体应当使用“名词”或者“形容词+名词”,且首字母必须大写。 |
说明:前缀为变量类型前缀。
【规则4-14】属性名用私有成员名称命名,但不带前缀,且首字母大写。 |
正例:
public class Hello
{
private string m_strName;
public string Name
{
get
{
return m_strName;
}
}
}
【规则4-15】方法名用大写字母开头的单词组合而成,且应当使用“动词”或者“动词+名词”(动宾词组)。 |
说明:方法名力求清晰、明了,通过方法名就能够判断方法的主要功能。方法名中不同意义字段之间不要用下划线连接,而要把每个字段的首字母大写以示区分。函数命名采用大小写字母结合的形式,但专有名词不受限制。
【规则4-16】To型方法:表示类型转换的方法一般用to开头。 |
说明:这些方法主要用来进行类型转换。
正例: ToString()
【规则4-17】遵循统一的规范来书写命名空间的声明,标识符用点号分隔开,且必须以ZTE开头。 |
说明:以ZTE开头,随后部分是系统、模块等。
【规则4-18】类名采用大小写结合的方法,构成类名的每个单词的首字母的首字母也必须大写。在构成类名的单词之间不用下划线。 |
说明:1. 名字应该能够标识事物的特性。
2. 名字尽量不使用缩写,除非它是众所周知的。
3. 名字可以有两个或三个单词组成,但通常不应多于三个。
4. 在名字中,所有单词第一个字母大写。
【规则4-19】接口命名在名字前加上“I”前缀,其它和类命名规范相同。 |
〖建议4-1〗尽量避免名字中出现数字编号,如Value1、Value2等,除非逻辑上的确需要编号。 |
〖建议4-2〗标识符前最好不加项目、产品、部门的标识。 |
说明:这样做的目的是为了代码的可重用性。
7 声明
【规则5-1】一行只声明一个变量。 |
正例:
int iLevel;
int iSize;
反例:
int iLevel, iSize;
【规则5-2】一个变量有且只有一个功能,不能把一个变量用于多种用途。 |
说明:一个变量只用来表示一个特定功能,不能把一个变量作多种用途,即同一变量取值不同时,其代表的意义也不同。
〖建议5-1〗变量声明应该只放在代码段的开始部分。最好不要到使用时才声明变量。对象类变量在函数体结束后,手工设置为null值,以利于资源的回收。 |
正例:
void Method()
{
int iSample = 0; //方法块的开始
//其它语句
}
8 表达式与语句
表达式是语句的一部分,它们是不可分割的。表达式和语句虽然看起来比较简单,但使用时隐患比较多。本章归纳了正确使用表达式和if、for、while、goto、switch等基本语句的一些规则与建议。
【规则6-1】一条语句只完成一个功能。 |
说明:复杂的语句阅读起来,难于理解,并容易隐含错误。变量定义时,一行只定义一个变量。
正例:
int iHelp;
int iBase;
int iResult;
iHelp = iBase;
iResult = iHelp + GetValue(iBase);
反例:
int iBase,
iResult; // 一行定义多个变量
iResult = iBase + GetValue(iBase); // 一条语句实现多个功能,iBase有两种用途。
【规则6-2】在表达式中使用括号,使表达式的运算顺序更清晰。 |
说明:由于将运算符的优先级与结合律熟记是比较困难的,为了防止产生歧义并提高可读性,即使不加括号时运算顺序不会改变,也应当用括号确定表达式的操作顺序。
正例:
if (((iYear % 4 == 0) && (iYear % 100 != 0)) || (iYear % 400 == 0))
反例:
if (iYear % 4 == 0 && iYear % 100 != 0 || iYear % 400 == 0)
【规则6-3】避免表达式中的附加功能,不要编写太复杂的复合表达式。 |
说明:带附加功能的表达式难于阅读和维护,它们常常导致错误。对于一个好的编译器,下面两种情况效果是一样的。
正例 :
ariVar[1] = ariVar[2] + ariVar[3];
ariVar[4]++;
iResult = ariVar[1] + ariVar[4];
ariVar[3]++;
反例:
iResult = (ariVar[1] = ariVar[2] + ariVar[3]++) + ++ariVar[4] ;
【规则6-4】不可将浮点变量用“==”或“!=”与任何数字比较。 |
说明:无论是float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该转化成“>=”或“<=”形式。
正例:
if ((fResult >= -EPSINON) && (fResult <= EPSINON))
反例:
if (fResult == 0.0) // 隐含错误的比较
其中EPSINON是允许的误差(即精度)。
【规则6-5】在switch语句中,每一个case分支必须使用break结尾,最后一个分支必须是default分支。 |
说明:避免漏掉break语句造成程序错误。同时保持程序简洁。
对于多个分支相同处理的情况可以共用一个break,但是要用注释加以说明。
正例:
switch (iMessage)
{
case SPAN_ON:
[处理语句]
break;
case SPAN_OFF:
[处理语句]
break;
default:
[处理语句]
break;
}
【规则6-8】不可在for 循环体内修改循环变量,防止for 循环失去控制。 |
〖建议6-1〗循环嵌套次数不大于3次。 |
〖建议6-2〗do while语句和while语句仅使用一个条件。 |
说明:保持程序简洁。如果需要判断的条件较多,建议用临时布尔变量先计算是否满足条件。
正例:
BOOLEAN bCondition;
do
{
……..
bCondition = ((tAp[iPortNo].bStateAcpActivity != PASSIVE)
|| (tAp[iPortNo].bStateLacpActivity != PASSIVE))
&& (abLacpEnabled[iPortNo])
&& (abPortEenabled[iPortNo])
} while (bCondition);
〖建议6-3〗当switch语句的分支比较多时,采用数据驱动方式。 |
说明:当switch 语句中case 语句比较多时,会降低程序的效率。
〖建议6-4〗如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体的外面。 |
说明:下面两个示例中,反例比正例多执行了NUM -1次逻辑判断。并且由于前者总要进行逻辑判断,使得编译器不能对循环进行优化处理,降低了效率。如果NUM非常大,最好采用正例的写法,可以提高效率。
const int NUM = 100000;
正例:
if (bCondition)
{
for (i = 0; i < NUM; i++)
{
DoSomething();
}
}
else
{
for (i = 0; i < NUM; i++)
{
DoOtherthing();
}
}
反例:
for (i = 0; i < NUM; i++)
{
if (bCondition)
{
DoSomething();
}
else
{
DoOtherthing();
}
}
〖建议6-5〗for语句的循环控制变量的取值采用“半开半闭区间”写法。 |
正例:
int aiScore[NUM];
…
for (i = 0; i < NUM; i++)
{
printf(“%d\n”,aiScore[i])
}
反例:
int aiScore[NUM];
…
for (i = 0; i <= NUM-1; i++)
{
printf(“%d\n”,aiScore[i]);
}
相比之下,正例的写法更加直观,尽管两者的功能是相同的。
9 类和接口
【规则7-1】类内部的代码布局顺序:数据成员、属性、构造函数、方法。 |
正例:
public class Sample
{
private int m_iProperty1; //数据成员
public int
Property1 //属性
{
get
{
return m_iProperty1;
}
set
{
m_iProperty1
= value;
}
}
public Sample() //构造函数
{
}
public string Operation1(long lParam1,
string strParam2) //方法
{
return null;
}
〖建议7-1〗功能相关的方法放在一起。 |
说明:如接口中关系较紧密的的几个方法,类属性的get和set 方法,有调用关系的方法,重载的方法等有相近或相关的方法尽可能放在一起,方便阅读。
〖建议7-2〗方法的参数个数不宜超过4个。 |
说明:过多的函数参数会导致性能降低。
〖建议7-3〗使程序结构体现程序的目的。 |
正例:
return
booleanExpression;
反例:
if
(booleanExpression)
{
return true;
}
else
{
return false;
}
〖建议7-4〗保证内部类定义成private,提高类的封装性。 |
〖建议7-5〗嵌套内部类不能超过两层。 |
〖建议7-6〗一个接口可以有多个实现类,实现类共同的变量在接口里声明。 |
附录A
(资料性附录)
编程模版
下面的例子显示了如何格式化包含单个public类的C#源文件。接口格式化与之类似,
using System;
namespace ZTE.xxx
{
/// <summary>
/// 版权所有(C)2004,中兴通讯
/// 内容摘要:
本文件的内容是…..,包括主要……模块、……函数及功能是…….
/// 完成日期:2004年3月1日
/// 版 本:V1.0
/// 作 者:小张
///
/// 修改记录1:
/// 修改日期:2004年3月10日
/// 版 本
号:V1.2
/// 修 改
人:小张
/// 修改内容:对方法……进行修改,修正故障BUG……。
/// 修改记录2:
/// 修改日期:2004年3月20日
/// 版 本
号:V1.3
/// 修 改
人:小张
/// 修改内容:对方法……进行进一步改进,修正故障……。
/// </summary>
public class Sample
{
//数据成员
private int m_iProperty1;
/// <summary>
/// 示例属性
/// </summary>
public int Property1
{
get
{
return m_iProperty1;
}
set
{
m_iProperty1
= value;
}
}
/// <summary>
/// 示例方法
/// </summary>
/// <param name="Param1">参数1</param>
/// <param name="Param2">参数2</param>
/// <returns>返回值</returns>
public string Operation1(long Param1, string Param2)
{
return null;
}
}
}