您的位置:首页 > 编程语言 > C#

C#代码 编写规范

2009-08-20 13:00 176 查看
1引言
1.1编写目的
根据公司发展的情况,为加强开发团队软件项目质量控制,规范软件开发流程,提高整体技术水平,撰写本文档。执行本规范的目标是保证团队产出的所有源代码都是架构清晰、逻辑关系直观易懂、易于阅读和理解的。督促开发人员养成良好的编码习惯,形成统一的编码风格。提高我们的软件产品的稳定性、安全性和易维护性。
1.2定义
文档中对于一些术语可能采用了不一致的名词,但是实际表达的是同一类别,如方法、过程、函数等表示同一元素。类、结构、记录等也表示同一类结构体。
2标准部分
2.1命名
对于理解应用程序的逻辑流,命名方案是最有影响力的一种帮助。名称应该说明“什么”而不是“如何”。通过避免使用公开基础实现(它们会发生改变)的名称,可以保留简化复杂性的抽象层。唯一名称在编程上仅用于将各项区分开。表现力强的名称是为了帮助人们阅读,请确保选择的名称符合适用语言的规则和标准。
例如,可以使用 GetNextStudent(),而不是 GetNextArrayElement()。
不要使用匈牙利命名法来命名变量。以前,很多程序员喜欢把数据类型作为变量名的前缀而m_作为成员变量的前缀。例如: string m_sName; int nAge;然而,这种方式在.NET编码规范中是不推荐的。
2.1.1常量
常量必须全部大写,如DEFAULT_FORMAT_TYPE,每个字母之间用下划线分隔。
2.1.2成员变量、局部变量、参数、成员字段
1、 变量名使用 camel 大小写处理 ,如documentFormatType,其中第一个单词的第一个字母小写,其他单词的第一个字母都是大写的。除非必要禁止使用下划线。
2、 只要合适,在变量名的末尾追加计算限定符(Avg、Sum、Min、Max、Index)。
3、 在关系密切的变量名中尽量使用互补对,用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。下面是一些在软件中常用的反义词组。
add / remove add / delete begin / end create / destroy
insert / delete first / last get / release put / get
increment / decrement lock / unlock open / close up / down min / max old / new start / stop source / destination cut / paste next / previous source / target show / hide send / receive
4、 布尔变量名应该尽量包含 Is,如 fileIsFound。可以使用时态表明状态。
5、 在命名状态变量时,避免使用诸如 Flag 的术语。状态变量不同于布尔变量的地方是它可以具有两个以上的可能值。不是使用 documentFlag,而是使用更具描述性的名称,如 documentFormatType。
6、 即使对于可能仅出现在几个代码行中的生存期很短的局部变量,仍然使用有意义的名称。仅对于短循环索引使用单字母变量名,如 i 或 j。在其他任何时候不要用单个字母的变量名。
2.1.3属性、类静态变量、方法、函数、过程
1、 方法名称应尽量采用动词+名次形式,如 CalculateInvoiceTotal(),也可以是动词或动词短语。 必须使用 Pascal 大小写处理(其中每个单词的第一个字母都是大写的),除非必要禁止使用下划线。
2、 方法名称应该能够充分的“自注释”,如 GetCurrentUserName()。方法名需能看出它作什么。别使用会引起误解的名字。
3、 属性以简洁清晰的名词命名
4、 普通类型的变量,只要用有意义的名字命名即可,不可使用简称和无意义的名称诸如A,x1等,如:CustomerName ,不能起太长的名字,应该尽量简洁,如VariableUsedToStoreSystemInformation,太复杂了,不要这么啰嗦。
5、 对于控件,应该指明控件的类型,方法是直接在变量后面加以类名:NextPageButton,。
2.1.4注释
1、 文件头部应进行注释,文件头注释必须放在文件中所有文字的最前面,注释必须列出:公司版权说明、项目名称、模块、版本号、完成日期、作者、内容、功能、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明。对于非私有的非局部的一切元素使用 XML 文档功能。每个方法的开始,提供标准的注释样本以指示用途、假设和限制。
2、 边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。总是使代码周围的注释保持最新。
3、 注释的内容要清楚、明了,含义准确,防止注释二义性。错误的注释不但无益反而有害。注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。放于后方的注释不应该超出代码行长度限制,否则不能折行,必须改放在上方。
4、 避免杂乱的或看起来漂亮的修饰性注释,如一整行星号或印刷框。而是应该使用空白将注释同代码分开。
5、 通过对函数或过程、变量、结构等正确的命名以及合理地组织代码的结构,使代码成为自注释的。清晰准确的函数、变量等的命名,可增加代码可读性,并减少不必要的注释。在代码的功能、意图层次上进行注释,提供有用、额外的信息。
6、 在编写注释时使用完整的句子。注释应该阐明代码,而不应该增加多义性。注释应考虑程序易读及外观排版的因素,使用的语言若是中、英兼有的,建议多使用中文,除非能用非常流利准确的英文表达。
7、 避免多余的或不适当的注释,如幽默的不主要的备注。
8、 为了防止问题反复出现,对错误修复和解决方法代码总是使用注释。
9、 对由复杂循环和逻辑分支组成的代码使用注释。可以有效帮助源代码读者。
10、 不要每行代码,每个声明的变量都做注释。在需要的地方注释。可读性强的代码需要很少的注释,如果所有的变量和方法的命名都很有意义,会使代码可读性很强并无需太多注释。
11、 在整个应用程序中,使用具有一致的标点和结构的统一样式来构造注释。行数不多的注释会使代码看起来优雅。但如果代码不清晰,可读性差,如果因为某种原因使用了复杂艰涩的原理,就必须为程序配备良好的文档和充分的注释。简言之,要写清晰,可读的代码以致无须什么注释就能理解。对注释做拼写检查,保证语法和标点符号的正确使用。
2.1.5类、枚举、结构、接口、模块
1、 类必须以名词或名词短语命名,体现类的作用。当类是一个特性(Attribute)时,以Attribute结尾,当类是一个异常(Exception)时,以Exception结尾。当类只用于作为其他类的基类,根据情况,以Base结尾。如果定义的类是一个窗体,那么名字的后面加后缀Form,如果是Web窗体,加后缀Page。
2、 必须使用 Pascal 大小写处理(其中每个单词的第一个字母都是大写的),除非必要禁止使用下划线。
3、 枚举和结构 同样必须以名词或名词短语命名。最好体现枚举或结构的特点。Enum ColorButtons 以复数结尾,表明这是一个枚举 ,Structure CustomerInfoRecord 以Record结尾,表明这是一个结构体。
4、 委托类型,普通的委托类型以描述动作的名词命名,以体现委托类型实例的功能。用于事件处理的委托类型,必须以EventHandler结尾,如: DataChangedEventHandler。
2.2源码格式
1、 建立标准的缩进大小(如四个空格或TAB),并一致地使用此标准。用规定的缩进对齐代码节。沿逻辑结构行缩进代码。没有缩进,代码将变得难以理解,缩进代码会产生出更容易阅读的代码。
2、 程序块的分界符(如C/C++语言的大括号‘{’和‘}’)应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体的开始、类的定义、结构的定义、枚举的定义以及if、for、do、while、switch、case语句中的程序都要采用如上的缩进方式。在括号对对齐的位置垂直对齐左括号和右括号,禁止其他自定义的格式,如:
for (i = 0; i < 100; i++)
{
...
}
3、 代码行和注释行的长度必须小于120个字符,长于标准长度的代码行必须折行并缩进,当一行被分为几行时,将串联运算符放在每一行的开头。长表达式要在低优先级操作符处划分新行,操作符放在新行之首,使排版整齐,语句可读,避免不得不滚动源代码编辑器,并且可以提供整齐的表示形式。若函数或过程中的参数较长,也要进行适当的划分。
4、 使用空白为源代码提供结构线索。这样做会创建代码“段”,有助于读者理解软件的逻辑分段。除非必要,每一行的语句应该只有一条,不允许把多个短语句写在一行中,禁止用一行完成一个for循环或if判断语句。if、for、do、while、case、switch、default等语句自占一行。 如下例子不符合规范
if (UserCR == null) return;
5、 源程序中关系较为紧密的代码应尽可能相邻。便于程序阅读和查找。以下代码布局不太合理。
rect.length = 10;
char_poi = str;
rect.width = 5;
若按如下形式书写,可能更清晰一些。
rect.length = 10;
rect.width = 5; // 矩形的长与宽关系较密切,放在一起。
char_poi = str;
2.3异常及错误处理
1、 不要“捕捉了异常却什么也不做”。如果隐藏了一个异常,你将永远不知道异常到底发生了没有。只捕捉特定的异常,而不是一般的异常。除非是一些非关键的你不在乎是否能够执行成功的语句才允许这样做。
2、 发生异常时,给出友好的消息给用户,但要精确记录错误的所有可能细节,包括发生的时间,和相关方法,类名,上下文环境等。
3、 错误信息需能帮助用户解决问题。永远别用象“应用程序出错”,“发现一个错误”等错误信息。而应给出象“更新数据库失败,请确保登陆id和密码正确。” 的具体消息。显示错误信息时,除了说哪里错了,还应提示用户如何解决问题。不要用象“更新数据库失败。”这样的,要提示用户怎么做:“更新数据库失败,请确保登陆id和密码正确。” 显示给用户的消息要简短而友好。但要把所有可能的信息都记录下来,以助诊断问题。
4、 不必在所有方法中捕捉一般异常。不管它,让程序崩溃。这将帮助你在开发周期发现大多数的错误。你可以用应用程序级(线程级)错误处理器处理所有一般的异常。
5、 不要在程序中的不同位置不同逻辑条件下引发的异常中使用同样的错误信息,否则当出现异常信息时将不能确定引起异常的原因,不能重现异常,开发人员就很难分析原因并修复程序错误。
6、 不必每个方法都用try-catch。当特定的异常可能发生时才使用。比如,当你写文件时,处理异常FileIOException。别写太大的 try-catch 模块。如果需要,为每个执行的任务编写单独的 try-catch 模块。这将帮你找出哪一段代码产生异常,并给用户发出特定的错误消息如果应用程序需要,可以编写自己的异常类。
好:
void ReadFromFile ( string fileName )
{
try
{
// read from file.
}
catch (FileIOException ex)
{
// log error.
// re-throw exception depending on your case.
throw;
}
}
不好:
void ReadFromFile ( string fileName )
{
try
{
// read from file.
}
catch (Exception ex)
{
// Catching general exception is bad… we will never know whether it
// was a file error or some other error.
// Here you are hiding an exception.
// In this case no one will ever know that an exception happened.
return "";
}
}
2.4其它注意事项
1、 使名称足够长以便有一定的意义,并且足够短以避免冗长。
2、 避免容易被主观解释的难懂的名称,如 方法名AnalyzeThis(),或者变量名 xxK8。这样的名称会导致多义性,而不仅仅是抽象。
3、 在类属性的名称中包含类名是多余的,如 Book.BookTitle。而是应该使用 Book.Title。
4、 尽量减少使用缩写,而是使用以一致方式创建的缩写。缩写应该只有一个意思;同样,每个缩写词也应该只有一个缩写。例如,如果用 min 作为 minimum 的缩写,那么在所有地方都应这样做;不要将 min 又用作 minute 的缩写。
5、 尽量不要使用原义数字或原义字符串,如 For i = 1 To 7。而是使用命名常数,如 For i = 1 To NUM_DAYS_IN_WEEK 以便于维护和理解。
6、 不要在方法间共享成员变量,如果在几个方法间共享一个成员变量,那就很难知道是哪个方法在什么时候修改了它的值。
7、 使用C# 或 VB.NET的特有类型,而不是System命名空间中定义的别名类型。如int而不是Int16、Int32。
8、 除非必要,不要用数字或较奇怪的字符来定义标识符。如下命名,使人产生疑惑,如EXAMPLE_0_TEST;void set_sls00( byte sls );
9、 不要在代码中使用具体的路径和驱动器名,使用相对路径,并使路径可编程。永远别设想你的代码是在“C:”盘运行。
10、 别把成员变量声明为 public或 protected。都声明为private 而使用 public/protected 的Properties。
11、 应用程序启动时应该“自检”并确保所需文件和附件在指定的位置。必要时检查数据库连接。出现任何问题给用户一个友好的提示。如果需要的配置文件找不到,应用程序需能自己创建使用默认值的一份。如果在配置文件中发现错误值,应用程序要抛出错误,给出提示消息告诉用户正确值。
2.5一般原则
1、 源代码从命名、排版、代码组织等方面应符合开发工具默认提供的方案。除非能够提供重大改进不要使用其它语言、工具提供的或专家推荐的编码方案,如果确实有好的方法,应在经过审核后加入本编码规范后推广使用。
2、 避免使用大文件。如果一个文件里的代码超过300~400行,必须考虑将代码分开到不同类中。避免写太长的方法。一个典型的方法代码在1~25行之间。如果一个方法发代码超过25行,应该考虑将其分解为不同的方法,但是代码行数不必拘泥于25行之内,这一数据已经有比较长的历史,不一定符合现在的情况,如果有很多重复同一功能的代码可以长一些。
3、 标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。一些单词有大家公认的缩写。
4、 注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级。不要使用难懂的技巧性很高的语句,除非很有必要时。
5、 防止局部变量与公共变量同名。若使用了较好的命名规则,那么此问题可自动消除。
6、 构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问的公共变量,防止多个不同模块或函数都可以修改、创建同一公共变量的现象。降低公共变量耦合度。
7、 结构(或类)的功能要单一,是针对一种事务的抽象。设计结构时应力争使结构代表一种现实事务的抽象,而不是同时代表多种。结构中的各元素应代表同一事务的不同侧面,而不应把描述没有关系或关系很弱的不同事务的元素放到同一结构中。不要设计面面俱到、非常灵活的数据结构。面面俱到、灵活的数据结构反而容易引起误解和操作困难。不同结构间的关系不要过于复杂。若两个结构间关系较复杂、密切,那么应合为一个结构。由于两个结构都是描述同一事物的,那么不如合成一个结构。
8、 对所调用函数的错误返回码要仔细、全面地处理。明确函数功能,精确(而不是近似)地实现函数设计。在同一项目组应明确规定对函数参数的合法性检查应由函数的调用者负责还是由函数本身负责,缺省是由函数调用者负责。。
9、 不要设计多用途面面俱到的函数。多功能集于一身的函数,很可能使函数的理解、测试、维护等变得困难。函数的功能应该是可以预测的,也就是只要输入数据相同就应产生同样的输出。
10、 设计高扇入、合理扇出(小于7)的函数。扇出是指一个函数直接调用(控制)其它函数的数目,而扇入是指有多少上级函数调用它。扇出过大,表明函数过分复杂,需要控制和协调过多的下级函数;而扇出过小,如总是1,表明函数的调用层次可能过多,这样不利程序阅读和函数结构的分析,并且程序运行时会对系统资源如堆栈空间等造成压力。函数较合理的扇出(调度函数除外)通常是3-5。扇出太大,一般是由于缺乏中间层次,可适当增加中间层次的函数。扇出太小,可把下级函数进一步分解多个函数,或合并到上级函数中。当然分解或合并函数时,不能改变要实现的功能,也不能违背函数间的独立性。扇入越大,表明使用此函数的上级函数越多,这样的函数使用效率高,但不能违背函数间的独立性而单纯地追求高扇入。公共模块中的函数及底层函数应该有较高的扇入。较良好的软件结构通常是顶层函数的扇出较高,中层函数的扇出较少,而底层函数则扇入到公共模块中。
11、 编程时要经常注意代码的效率。代码效率分为全局效率、局部效率、时间效率及空间效率。全局效率是站在整个系统的角度上的系统效率;局部效率是站在模块或函数角度上的效率;时间效率是程序处理输入任务所需的时间长短;空间效率是程序所需内存空间。局部效率应为全局效率服务,不能因为提高局部效率而对全局效率造成影响。在保证软件系统的正确性、稳定性、可读性及可测性的前提下,提高代码效率。不能一味地追求代码效率,而对软件的正确性、稳定性、可读性及可测性造成影响。例如应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作量最小,从而提高程序的时间效率。尽量减少循环嵌套层次。
如下代码效率不高。
for (ind = 0; ind < MAX_ADD_NUMBER; ind++)
{
sum += ind;
backSum = sum;
}
语句“back_sum = sum;”完全可以放在for语句之后,如下。
for (ind = 0; ind < MAX_ADD_NUMBER; ind++)
{
sum += ind;
}
backSum = sum;
12、 不应花过多的时间拼命地提高调用不很频繁的函数代码效率。不要一味追求紧凑的代码。对代码优化可提高效率,但若考虑不周很有可能引起严重后果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: