前言

编写本标准的目的是为了统一软件编程风格,提高软件源程序的可读性、可靠性和可重用性,提高软件源程序的质量和可维护性,减少软件维护成本,最终提高软件产品生产力。
本规范分成规则性和建议性两种:对于规则性规范,要求所有软件开发人员严格执行;对于建议性规范,各项目编程人员可以根据实际情况选择执行。本规范的示例都以C#语言描述。
本规范的内容包括:基本原则、布局、注释、命名规则、声名、表达式与语句、类与接口等。规范最后给出了标准模版供软件人员参考。
自本标准实施之日起,以后新编写的和修改的代码均应执行本标准。

范围

  1. 本标准规定了C#语言的编程规范,主要包括基本原则、布局、注释、命名规则、声明、表达式与语句、类与接口等。<br /> 本标准适用于使用C#语言编码的所有软件。本规范自生效之日起,对以后新编写的和修改的代码有约束力。

术语和定义

下列术语和定义适用于本标准。

  • 原则

编程时应该坚持的指导思想。
【原则1-1】首先是为人编写程序,其次才是计算机。
说明:这是软件开发的基本要点,软件的生命周期贯穿产品的开发、测试、生产、用户使用、版本升级和后期维护等长期过程,只有易读、易维护的软件代码才具有生命力。
【原则1-2】保持代码的简明清晰,避免过分的编程。
说明:简单是最美。保持代码的简单化是软件工程化的基本要求。不要过分追求技巧,否则会降低程序的可读性。
【原则1-3】所有的代码尽量遵循公共语言规范(CLS)。
说明:编程时以该规范为准,规范没有规定的内容参考上面的标准。
【原则1-4】编程时首先达到正确性,其次考虑效率。
说明:编程首先考虑的是满足正确性、健壮性、可维护性、可移植性等质量因素,最后才考虑程序的效率和资源占用。
【原则1-5】尽量避免使用GOTO语句。
【原则1-6】尽可能重用、修正老的代码。
说明:尽量选择可借用的代码,对其修改优化以达到自身要求。
【原则1-7】 尽量减少同样的错误出现的次数。
说明:事实上,我们无法做到完全消除错误,但通过不懈的努力,可以减少同样的错误出现的次数。

  • 建议

编程时必须加以考虑的约定。

  • 说明

对此规则或建议的必要的解释。

  • 正例

对此规则或建议给出的正确例子。

  • 反例

对此规则或建议给出的反面例子。

布局

程序布局的目的是显示出程序良好的逻辑结构,提高程序的准确性、连续性、可读性、可维护性。更重要的是,统一的程序布局和编程风格,有助于提高整个项目的开发质量,提高开发效率,降低开发成本。同时,对于普通程序员来说,养成良好的编程习惯有助于提高自己的编程水平,提高编程效率。因此,统一的、良好的程序布局和编程风格不仅仅是个人主观美学上的或是形式上的问题,而且会涉及到产品质量,涉及到个人编程能力的提高,必须要引起重视。

| 【规则2-1-1】源代码文件(.cs)的布局顺序是:using语句、命名空间、注释、类。

  1. |

| —- |

说明:以下内容如果某些节不需要,可以忽略。但是其它节要保持该次序。
正例:

using System;

namespace lanmage.xxx
{
///


/// 版权所有: 版权所有(C) 2004
/// 内容摘要: 本类是…..,包括主要……模块、……函数及功能是…….
/// 完成日期: 输入完成日期,例:2004年3月1日
/// 版 本:
/// 作 者:
///
/// 修改记录1: 修改历史记录,包括修改日期、修改者及修改内容
/// 修改日期:
/// 版 本 号:
/// 修 改 人:
/// 修改内容:
/// 修改记录2: …
///

public class Sample
{
}

基本格式

规则

编程时必须遵守的约定。

| 【规则2-1-2】遵循统一的布局顺序来书写using语句,不同类别的using语句之间用空行分隔。

  1. |

| —- |

说明:using命名空间语句的排列顺序为System开头的命名空间在最前面,接下来是引自外部的命名空间,再接下来是应用程序自身的命名空间,即using 中标准的命名空间要在本地的命名空间之前,而且按照字母顺序排列。
正例:
using System; // .Net自身的
using System.Data;

using FarPoint.Win.Spread; //第三方的

using lanmage.DSS.Public; //程序自身的

| 【规则2-1-3】程序中一行的代码和注释不能超过80字符。

  1. |

| —- |

说明:包括空格在内不超过80字符。

| 【规则2-1-4】if、else、else if、for、while、do等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加 { }。

  1. |

| —- |

说明:这样可以防止书写失误,也易于阅读。
正例:
if (varible1 < varible2)
{
varible1 = varible2;
}
反例:下面的代码执行语句紧跟if的条件之后,而且没有加{},违反规则。

if (varible1 < varible2) varible1 = varible2;

| 〖建议2-1-4〗源程序中关系较为紧密的代码应尽可能相邻。

  1. |

| —- |

说明:这样便于程序阅读和查找。
正例:
iLength = 10;
iWidth = 5; // 矩形的长与宽关系较密切,放在一起。
StrCaption = “Test”;
反例:
iLength = 10;
strCaption = “Test”;
iWidth = 5;

对齐

| 【规则2-2-1】 禁止使用TAB键,必须使用空格进行缩进。缩进为4个空格。

  1. |

| —- |

说明:消除不同编辑器对TAB处理的差异,有的代码编辑器可以设置用空格代替TAB键。

| 【规则2-2-2】程序的分界符‘{’和‘}’应独占一行并且位于同一列,同时与引用它们的语句左对齐。{ }之内的代码块使用缩进规则对齐。

  1. |

| —- |

说明:这样使代码便于阅读,并且方便注释。
do while语句和结构的类型化时可以例外,while条件和结构名可与 } 在同一行。
正例:
void Function(int iVar)
{ // 独占一行并与引用语句左对齐。
while (condition)
{
DoSomething(); // 与{ }缩进4格
}
}
反例:
void Function(int iVar){
while (condition){
DoSomething();
}}

| 【规则2-2-3】相关的赋值语句等号对齐。

  1. |

| —- |

正例:
tPDBRes.wHead = 0;
tPDBRes.wTail = wMaxNumOfPDB - 1;
tPDBRes.wFree = wMaxNumOfPDB;
tPDBRes.wAddress = wPDBAddr;
tPDBRes.wSize = wPDBSize;

空行空格

| 【规则2-3-1】不同逻辑程序块之间要使用空行分隔。

  1. |

| —- |

说明:空行起着分隔程序段落的作用。适当的空行可以使程序的布局更加清晰。
正例:
void Hey(void)
{
[Hey实现代码]
}
// 空一行
void Ack(void)
{
[Ack实现代码]
}
反例:
void Hey(void)
{
[Hey实现代码]
}
void Ack(void)
{
[Ack实现代码]
}
// 两个函数的实现是两个逻辑程序块,应该用空行加以分隔。

| 【规则2-3-2】一元操作符如“!”、“~”、“++”、“—”、“*”、“&”等前后不加空格。“[]”、“.”这类操作符前后不加空格。

  1. |

| —- |

正例:
!bValue
~iValue
++iCount
&fSum
aiNumber[i] = 5;
tBox.dWidth

| 【规则2-3-3】多元运算符和它们的操作数之间至少需要一个空格。

  1. |

| —- |

正例:
fValue = fOldValue;
fTotal + fValue
iNumber += 2;

| 【规则2-3-4】关键字之后要留空格。

  1. |

| —- |

说明:if、for、while等关键字之后应留一个空格再跟左括号‘(’,以突出关键字。

| 【规则2-3-5】函数名之后不要留空格。

  1. |

| —- |

说明:函数名后紧跟左括号‘(’,以与关键字区别。

| 【规则2-3-6】‘(’向后紧跟,‘)’、‘,’、‘;’向前紧跟,紧跟处不留空格。‘,’之后要留空格。‘;’不是行结束符号时其后要留空格。

  1. |

| —- |

正例:
例子中的 代表空格。
for(i=0;i<MAX_BSC_NUM;i++)
{
DoSomething(iWidth,iHeight);
}

| 【规则2-3-7】注释符与注释内容之间要用一个空格进行分隔。

  1. |

| —- |

正例:
/ 注释内容 /
// 注释内容
反例:
/注释内容/
//注释内容

| 【规则2-3-8】集合与花括号:集合的左右两边的花括号,与集合的元素空一格。

  1. |

| —- |

正例:
string[] carTypes = {“Ford”, “afakh”, “xiaopeijian” };
int[] myInts = {10, 20, 30, 40, -20, 100};
反例:
string[] carTypes = {“Ford”, “afakh”, “xiaopeijian”};
int[] myInts = {10, 20, 30, 40, -20, 100};

断行

| 【规则2-4-1】长表达式(超过120列)要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐。

  1. |

| —- |

说明:条件表达式的续行在第一个条件处对齐。
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】函数声明时,类型与名称不允许分行书写。

  1. |

| —- |

正例:
double CalcArea(double dWidth, double dHeight);
反例:
double
CalcArea(double dWidth, double dHeight);

注 释

注释有助于理解代码,有效的注释是指在代码的功能、意图层次上进行注释,提供有用、额外的信息,而不是代码表面意义的简单重复。

| 【规则3-1】类、方法、属性的注释采用XML文档格式注释。代码间多行注释为“//”,单行注释采用“// …”。

  1. |

| —- |


正例:public class Sample
{
//数据成员 (单行注释)
private int m_iProperty1;

///

(XML注释)
/// 示例属性
///

public int Property1
{
get
{
return m_iProperty1;
}
/ set ( 多行注释)
{
m_iProperty1 = value;
}
/
}

| 【规则3-2】一般情况下,源程序有效注释量必须在20%以上。

  1. |

| —- |


说明:注释的原则是有助于对程序的阅读理解,注释不宜太多也不能太少,注释语言必须准确、易懂、简洁。有效的注释是指在代码的功能、意图层次上进行注释,提供有用、额外的信息。

| 【规则3-3】注释使用中文。

  1. |

| —- |


说明:对于特殊要求的可以使用英文注释,如工具不支持中文或国际化版本时。

| 【规则3-4】类、接口头部应进行XML注释。

  1. |

| —- |

说明:注释必须列出:内容摘要、版本号、作者、完成日期、修改信息等。
正例:
///


/// 版权所有: 版权所有(C) 2004
/// 内容摘要: 本类的内容是…..
/// 完成日期:2004年3月1日
/// 版 本:V1.0
/// 作 者:小张
///
/// 修改记录1:
/// 修改日期:2004年3月10日
/// 版 本 号:V1.2
/// 修 改 人:小张
/// 修改内容:对方法……进行修改,修正故障BUG……。
/// 修改记录2:
/// 修改日期:2004年3月20日
/// 版 本 号:V1.3
/// 修 改 人:小张
/// 修改内容:对方法……进行进一步改进,修正故障……。
///

| 【规则3-5】公共方法前面应进行XML注释,列出:函数的目的/功能、输入参数、返回值等。

  1. |

| —- |


| 【规则3-6】保证代码和注释的一致性。修改代码同时修改相应的注释,不再有用的注释要删除。

  1. |

| —- |

| 【规则3-7】注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。

  1. |

| —- |

说明:在使用缩写时或之前,应对缩写进行必要的说明。
正例:
如下书写比较结构清晰

/ 获得子系统索引 /
iSubSysIndex = aData[iIndex].iSysIndex;

/ 代码段1注释 /
[ 代码段1 ]

/ 代码段2注释 /
[ 代码段2 ]
反例1
如下例子注释与描述的代码相隔太远。
/ 获得子系统索引 /

iSubSysIndex = aData[iIndex].iSysIndex;
反例2
如下例子注释不应放在所描述的代码下面。

iSubSysIndex = aData[iIndex].iSysIndex;
/ 获得子系统索引 /
反例3
如下例子,显得代码与注释过于紧凑。
/ 代码段1注释 /
[ 代码段1 ]
/ 代码段2注释 /
[ 代码段2 ]

| 【规则3-8】注释与所描述内容进行同样的缩排。

  1. |

| —- |



说明:可使程序排版整齐,并方便注释的阅读与理解。
正例:
如下注释结构比较清晰
int DoSomething(void)
{
/ 代码段1注释 /
[ 代码段1 ]

/ 代码段2注释 /
[ 代码段2 ]
}

反例
如下例子,排版不整齐,阅读不方便;
int DoSomething(void)
{
/ 代码段1注释 /
[ 代码段1 ]

/ 代码段2注释 /
[ 代码段2 ]
}

| 【规则3-9】对分支语句(条件分支、循环语句等)必须编写注释。

  1. |

| —- |



说明:这些语句往往是程序实现某一特殊功能的关键,对于维护人员来说,良好的注释有助于更好的理解程序,有时甚至优于看设计文档。

| 〖建议3-10〗通过对函数或过程、变量、结构等正确的命名以及合理地组织代码结构,使代码成为自注释的。

  1. |

| —- |



说明:清晰准确的函数、变量命名,可增加代码的可读性,减少不必要的注释。

| 〖建议3-11〗尽量避免在注释中使用缩写,特别是不常用缩写。

  1. |

| —- |



说明:在使用缩写时,应对缩写进行必要的说明。