C#编程规范

改动记录

Ver. No

发版日期

编制人

批准人

改动的说明

 

本规范包含两个个部分:“命名规范”、“代码格式”。

编写此规范的目的是,为大家编写清晰、易读的代码提供良好的建议。也为公司的代码批阅提供一个可供參考的标准。

C#编码规范的主要内容来自于MSDN中《Design Guidelines for Class Library Developers》,其次是摩托罗拉(中国)电子有限公司陈世忠编著的《C++编码规范》。另外,也參考了作者主持反编译的ASP
.net源代码、Microsoft公开源代码的.NET平台实现Rotor的系统类库、ErichGamma等的《设计模式——可复用面向对象软件的基础》、Bjarne
Stroustrup的《The C++ Programming Language》、以及作者在使用C#进行编码工作过程中积累的一些工作经验。

.NET Framework SDK提供了三种大写样式提供參考。分别:

Ø 
Pascal大写和小写

Ø 
Camel大写和小写

Ø  大写

大写和小写

将标识符的首字母和后面连接的每一个单词的首字母都大写。能够对三字符或很多其它字符的标识符使用 Pascal大写和小写。

比如:

BackColor

大写和小写

标识符的首字母小写,而每一个后面连接的单词的首字母都大写。

比如:

backColor

标识符中的全部字母都大写。仅对于由两个或者更少字母组成的标识符使用该约定。

比如:

System.IO

System.Web.UI

可能还必须大写标识符以维持与现有非托管符号方案的兼容性,在该方案中全部大写字母经经常使用于枚举和常数值。普通情况下,在使用它们的程序集之外这些字符应当是不可见的。

大写和小写规则使用參考表

标识符

大写和小写

演示样例

备注

Pascal

AppDomain

枚举类型

Pascal

ErrorLevel

枚举值

Pascal

FatalError

event

Pascal

ValueChange

异常类

Pascal

WebException

注意总是以Exception后缀结尾。

仅仅读的静态field

Pascal

RedValue

接口

Pascal

IDisposable

注意总是以I前缀開始。

方法

Pascal

ToString

命名空间

Pascal

System.Drawing

參数

Camel

typeName

属性

Pascal

BackColor

受保护的实例field

Camel

_redValue

注意

非常少使用。属性优于使用受保护的实例field。

公共实例field

Pascal

RedValue

注意非常少使用。

属性优于使用公共实例field。

为了避免混淆和保证跨语言交互操作。请遵循有关区分大写和小写的使用的下列规则:

1、不要使用要求区分大写和小写的名称。

对于区分大写和小写和不区分大写和小写的语言,组件都必须全然能够使用。不区分大写和小写的语言无法区分同一上下文中仅大写和小写不同的两个名称。因此,在创建的组件或类中必须避免这样的情况。

2、不要创建仅是名称大写和小写有差别的两个命名空间。

比如,不区分大写和小写的语言无法区分下面两个命名空间声明。

namespace ee.cummings;

namespace Ee.Cummings;

3、不要创建具有仅是大写和小写有差别的參数名称的函数。

以下的演示样例是不对的。

void MyFunction(string a, string A)

4、不要创建具有仅是大写和小写有差别的类型名称的命名空间。

在以下的演示样例中,Point p和 POINT p
是不适当的类型名称,原因是它们仅是大写和小写有差别。

System.Windows.Forms.Point p

System.Windows.Forms.POINT p

5、不要创建具有仅是大写和小写有差别的属性名称的类型。

在以下的演示样例中。int Color和 int COLOR
是不适当的属性名称,原因是它们仅是大写和小写有差别。

int Color {get, set}

int COLOR {get, set}

6、不要创建具有仅是大写和小写有差别的方法名称的类型。

在以下的演示样例中,calculate和 Calculate
是不适当的方法名称,原因是它们仅是大写和小写有差别。

void calculate()

void Calculate()

为了避免混淆和保证跨语言交互操作,请遵循有关区缩写的使用的下列规则:

1、不要将缩写或缩略形式用作标识符名称的组成部分。

比如,使用 GetWindow,而不要使用 GetWin。

2、不要使用计算机领域中未被普遍接受的缩写。

3、在适当的时候,使用众所周知的缩写替换冗长的词组名称。

比如,用 UI作为 User Interface
的缩写,用 OLAP作为 On-line Analytical Processing的缩写。

4、在使用缩写时,对于超过两个字符长度的缩写请使用 Pascal大写和小写。

比如。使用 HtmlButton或 HTMLButton。可是,应当大写仅有两个字符的缩写,如。System.IO,而不是
System.Io。

避免使用与经常使用的 .NET框架命名空间反复的类名称。比如。不要将下面不论什么名称用作类名称:System、Collections、Forms或
UI。有关 .NET框架命名空间的列表,请參阅类库。

另外,避免使用和下面keyword冲突的标识符。

AddHandler

AddressOf

Alias

And

Ansi

As

Assembly

Auto

Base

Boolean

ByRef

Byte

ByVal

Call

Case

Catch

CBool

CByte

CChar

CDate

CDec

CDbl

Char

CInt

Class

CLng

CObj

const

CShort

CSng

CStr

CType

Date

Decimal

Declare

Default

Delegate

Dim

Do

Double

each

else

elseIf

end

enum

erase

error

Event

Exit

ExternalSource

false

Finalize

Finally

Float

For

friend

function

get

GetType

goto

handles

If

Implements

Imports

In

inherits

Integer

Interface

Is

Let

Lib

like

Long

Loop

Me

Mod

Module

MustInherit

MustOverride

MyBase

MyClass

Namespace

New

Next

Not

Nothing

NotInheritable

NotOverridable

Object

On

Option

Optional

Or

Overloads

Overridable

Overrides

ParamArray

Preserve

Private

Property

Protected

Public

RaiseEvent

ReadOnly

ReDim

Region

REM

RemoveHandler

Resume

Return

Select

Set

Shadows

Shared

Short

Single

Static

Step

Stop

String

Structure

Sub

SyncLock

Then

Throw

To

True

Try

TypeOf

Unicode

Until

volatile

When

While

With

WithEvents

WriteOnly

Xor

eval

extends

instanceof

package

var

命名Namespace时的一般性规则是使用公司名称,后跟技术名称和可选的功能与设计,例如以下所看到的。

CompanyName.TechnologyName[.Feature][.Design]

比如:

Microsoft.Media

Microsoft.Media.Design

给命名空间名称加上公司名称或者其它知名商标的前缀能够避免两个已经公布的命名空间名称同样的可能性。

比如,Microsoft.Office是由 Microsoft
提供的 Office Automation Classes的一个适当的前缀。

在第二级分层名称上使用稳定的、公认的技术名称。将组织层次架构用作命名空间层次架构的基础。命名一个命名空间,该命名空间包括为具有 .Design后缀的基命名空间提供设计时功能的类型。比如。System.Windows.Forms.Design命名空间包括用于设计基于
System.Windows.Forms的应用程序的设计器和相关的类。

嵌套的命名空间应当在包括它的命名空间中的类型上有依赖项。

比如,System.Web.UI.Design中的类依赖于 System.Web.UI
中的类。可是,System.Web.UI中的类不依赖于 System.UI.Design
中的类。

应当对命名空间使用 Pascal大写和小写,并用句点分隔逻辑组件,如 Microsoft.Office.PowerPoint中所看到的。假设您的商标使用非传统的大写和小写,请遵循您的商标所定义的大写和小写,即使它与规定的
Pascal大写和小写相背离。

比如,命名空间 NeXT.WebObjects
和 ee.cummings 阐释了对于 Pascal大写和小写规则的适当背离。

假设在语义上适当,使用复数命名空间名称。

比如。使用 System.Collections而不是 System.Collection。此规则的例外是商标名称和缩写。比如,使用
System.IO而不是 System.IOs。

不要为命名空间和类使用同样的名称。

比如,不要既提供 Debug命名空间也提供 Debug
类。

最后,请注意命名空间名称不必非得与程序集名称相似。比如,假设命名程序集 MyCompany.MyTechnology.dll,它没有必要非得包括 MyCompany.MyTechnology命名空间。

下面规则概述命名类的指南:

1、使用名词或名词短语命名类。

2、使用 Pascal大写和小写。

3、少用缩写。

4、不要使用类型前缀。

如在类名称上对类使用 C前缀。比如。使用类名称 FileStream,而不是 CFileStream。

5、不要使用下划线字符 (_)。

6、有时候须要提供以字母 I開始的类名称。尽管该类不是接口。

仅仅要 I
是作为类名称组成部分的整个单词的第一个字母,这便是适当的。

比如,类名称 IdentityStore是适当的。

7、在适当的地方。使用复合单词命名派生的类。

派生类名称的第二个部分应当是基类的名称。

比如。ApplicationException对于从名为 Exception
的类派生的类是适当的名称。原因是 ApplicationException是一种 Exception。

请在应用该规则时进行合理的推断。比如。Button对于从
Control 派生的类是适当的名称。

虽然button是一种控件。可是将 Control作为类名称的一部分将使名称不必要地加长。

以下是正确命名的类的演示样例。

public class FileStream

public class Button

public class String

下面规则概述接口的命名指南:

1、用名词或名词短语,或者描写叙述行为的形容词命名接口。

比如,接口名称 IComponent使用描写叙述性名词。接口名称 ICustomAttributeProvider使用名词短语。名称 IPersistable
使用形容词。

2、使用 Pascal大写和小写。

3、少用缩写。

4、给接口名称加上字母 I前缀,以指示该类型为接口。

5、在定义类/接口对(当中类是接口的标准实现)时使用相似的名称。

两个名称的差别应该仅仅是接口名称上有字母 I前缀。

6、不要使用下划线字符 (_)。

下面是正确命名的接口的演示样例。

public interface IServiceProvider

public interface IFormatable

下面代码演示样例阐释怎样定义 IComponent接口及其标准实现 Component
类。

public
interface IComponent

{

// Implementation code goes here.

}

public
class Component: IComponent

{

// Implementation code goes here.

}

应该总是将后缀 Attribute加入到自己定义Attribute类。

下面是正确命名的Attribute类的演示样例。

public class ObsoleteAttribute

{

}

枚举 (Enum)值类型从 Enum
类继承。

下面规则概述枚举的命名指南:

1、对于 Enum类型和值名称使用 Pascal
大写和小写。

2、少用缩写。

3、不要在 Enum类型名称上使用 Enum
后缀。

4、对大多数 Enum类型使用单数名称,可是对作为位域的 Enum
类型使用复数名称。

5、总是将 FlagsAttribute加入到位域 Enum
类型。

Field应该以_开头。_表示Member。

比如

private OleDbConnection _connection =
null;

非静态field也能够下面命名方式,比如:

private string _id;[1]

在微软发布的共享版的C#代码中,採用的“_”前缀的风格,在《设计模式》一书中的全部源代码也是使用“_”风格。

下面规则概述静态Field的命名指南:

1、使用名词、名词短语或者名词的缩写命名静态field。

2、使用 Pascal大写和小写。

4、对静态field名称使用匈牙利语表示法前缀。

5、建议尽可能使用静态属性而不是公共静态field。

下面规则概述參数的命名指南:

1、使用描写叙述性參数名称。

參数名称应当具有足够的描写叙述性,以便參数的名称及其类型可用于在大多数情况下确定它的含义。

2、对參数名称使用 Camel大写和小写。

3、使用描写叙述參数的含义的名称。而不要使用描写叙述參数的类型的名称。

开发工具将提供有关參数的类型的有意义的信息。因此。通过描写叙述意义,能够更好地使用參数的名称。少用基于类型的參数名称,仅在适合使用它们的地方使用它们。

4、不要使用保留的參数。

保留的參数是专用參数,假设须要。能够在未来的版本号中公开它们。相反,假设在类库的未来版本号中须要很多其它的数据。请为方法加入新的重载。

5、不要给參数名称加匈牙利语类型表示法的前缀。

下面是正确命名的參数的演示样例。

Type GetType(string typeName)

string Format(string format, object[] args)

下面规则概述方法的命名指南:

使用动词或动词短语命名方法。

使用 Pascal大写和小写。

下面是正确命名的方法的实例。

RemoveAll()

GetCharArray()

Invoke()

在Java语言流行的编码风格中。行使用camel大写和小写命名方法,在《C++编码规范》(陈世忠编著人民邮电出版社),也是建议使用camel大写和小写。本规范中採用的是MSDN中建议的C#命名规则,和系统类库的命名规则一致。

下面规则概述属性的命名指南:

1、使用名词或名词短语命名属性。

2、使用 Pascal大写和小写。

3、不要使用匈牙利语表示法。

4、考虑用与属性的基础类型同样的名称创建属性。

比如,假设声明名为 Color的属性,则属性的类型相同应该是 Color。请參阅本主题中后面的演示样例。

下面代码演示样例阐释正确的属性命名。

public
class SampleClass

{

public Color BackColor

{

// Code for Get and Set accessors goes here.

}

}

下面代码演示样例阐释提供其名称与类型同样的属性。

public
enum Color

{

// Insert code for Enum here.

}

public
class Control

{

public Color Color

{

get

{

// Insert code here.

}

set

{

// Insert code here.

}

}

}

下面代码演示样例不对。原因是 Color属性是 Integer
类型的。

public
enum Color

{

// Insert code for Enum here.

}

public
class Control

{

public
int Color

{

get

{

// Insert code here.

}

set

{

// Insert code here.

}

}

}

在不对的演示样例中,不可能引用 Color枚举的成员。Color.Xxx
将被解释为訪问一个成员,该成员首先获取 Color属性(在 Visual Basic
中为 Integer类型,在 C#
中为 int类型)的值。然后再訪问该值的某个成员(该成员必须是 System.Int32的实例成员)。

下面规则概述event的命名指南:

1、对event处理程序名称使用 EventHandler后缀。

2、定两个名为 sender和 e
的參数。

sender 參数表示引发event的对象。sender參数始终是 object
类型的,即使在能够使用更为特定的类型时也如此。与event相关联的状态封装在名为 e的event类的实例中。对 e參数类型使用适当而特定的event类。

3、 EventArgs后缀命名event參数类。

5、要在类型的event声明上使用前缀或者后缀。

比如。使用 Close,而不要使用 OnClose。

6、常情况下。对于能够在派生类中重写的event,应在类型上提供一个受保护的方法(称为 OnXxx)。此方法仅仅应具有event參数
e,由于发送方总是类型的实例。

(补充样例)

下面演示样例阐释具有适当名称和參数的event处理程序。

public delegatevoid MouseEventHandler(object sender, MouseEventArgs e);

下面演示样例阐释正确命名的event參数类。

public
class MouseEventArgs : EventArgs

{

int x;

int y;

public MouseEventArgs(int x,int y)

{

this.x = x;

this.y = y;

}

public
int X

{

get

{

return x;

}

}

public
int Y

{

get

{

return y;

}

}

}

控件的命名。曾经缀作为标识某种类型的控件。

详细例如以下:

控件

前缀

说明

DropDownList

ddl

TextBox

txt

ListBox

lst

Literal

lt

LinkButton

lbn

Button

btn

Lable

lbl

DataGrid

dg

DataList

dtl

Table

tb

TableRow

tr

TableCell

tc

CheckBox

chk

CheckBoxList

ckl

RadioButton

rbn

RadioButtonList

rbl

ImageButton

ibn

HyperLink

hpl

Image

img

Calendar

cld

AdRotator

art

RequiredFieldValidator

vrf

CompareValidator

vcp

RangeValidator

vrg

Ledger

Ldg

假设页面中,仅仅有一个Ledger控件。建议使用ledger的小写全称,这样更直观。

Toolbar

toolbar

因为一个页面中通常仅仅有一个toolbar,使用全称的小写更直观。

Statusbar

statusbar

因为一个页面中通常仅仅有一个statusbar,使用全称的小写更直观。

局部变量的命名,不建议採用全部的变量在函数头声明,声明变量的原则是。以逻辑单元划分。在离使用的地方近期的位置声明变量通常可以使代码变得更清晰。

局部变量的命名建议採用Camel大写和小写。比如

DataTable dataTable;

对于for循环的变量名。继续使用i、j、k。

for(int i=0; i<10; i++)

{

for(int j=0; j<20; j++)

{

}

}

2.18 集合和数组变量的命名

集合变量的命名使用List作为后缀。数组变量的命名使用Array后缀,比使用复数形式更清晰。

比如:

WfActivityCollection activityList = // get collection

foreach(WfActivity activity
in activityList)

{

}

WfActivity[] activityArray = // get array

在系统中。有一些常常出现的,用途一致的,建议採用统一的变量命名风格。下面是參考。但不做硬性要求。

命名參考

命名

类型

用途/说明

pramName

string

在Web应用程序中,參数值所相应的变量。比如:

pramName = Request.QueryString[“Name”];

sql

string

Sql语句的变量。比如:string sql;

_id

Guid

私有field。比如:private Guid _id;

_name

string

私有field。

比如:private Guid _name;

_desc

string

私有field。

作为Description的缩写。

比如:

private string _desc;

ID

Guid

属性,比如:

public Guid ID

{

get

{

return
this. _id;

}

}

GetEntry()

方法

方法名。

用户获取实体对象的实例。比如:

public static User GetEntry(DataRow datarow)

{

}

GetEntryList

方法

方法名。用于返回实体对象的集合。比如:

public staticvoid GetEntryList(out DataTable dataTable)

{

}

searchKeyword

string

參数名。查询keyword。

public staticvoid GetEntryList(

out DataTable outDataTable,

string searchKeyword

)

{

}

dataTable

DataTable局部变量

DataTable类型的局部參数。

DataTable dataTable;

dataRow

DataRow局部变量

DataRow类型的局部參数。

DataRow dataRow;

dataTable

DataTable类型參数

DataTable类型參数。比如:

public static
void GetEntryList(out DataTable dataTable)

item

參数

在一些方法的參数中使用。比如:

public int IndexOf(Useritem)

{

}

index

參数

在表示索引值的參数。比如:

public RemoveAt(int index)

{

}

通常来说,WebUI层的代码会占整个project的代码的60%以上。所以说。WebUI层的编码规范尤其重要。

在页面中声明全局变量theForm,在window_onload时初始化,然后使用。

比如:

在页面PersonInfo.aspx文件里。Form的名字是PersonInfo,在某函数中须要訪问当中的文本框txtName的值时,代码应该这样写:

<Scriptlanguage="javascript">

<!--

var theForm;
//声明theForm变量,在window_onload事件中初始化。

function window_onload()

{

theForm = PersonInfo;

}

function toolbar_onclick(evt)

{

//这样做,比直接使用PersonInfo.txtName清晰多了

theForm.txtName.value =
“xxxxxxxxxxxxx”;

}

//-->

</Script>

假设页面须要一些初始化操作,响应的函数,建议统一使用window_onload的命名。比如:

<head>

<Scriptlanguage="javascript">

<!--

function window_onload()

{

// do something

}

//-->

</Script>

</head>

<bodyonload="window_onload();">

使用ShowDialogBox弹出的页面。通常须要有返回值处理,同一时候须要对Esc键响应关闭窗体。对此类代码的写法规范例如以下:

<SCRIPTlanguage="javascript">

<!--

var pageReturnValue;

function window_onbeforeunload()

{

window.returnValue = pageReturnValue;

}

function document_onkeydown()

{

if(event.keyCode == 27)

{

window.close();

}

}

//-->

</SCRIPT>

<SCRIPTLANGUAGE="javascript"FOR="document"EVENT="onkeydown">

<!--

document_onkeydown()

//-->

</SCRIPT>

</head>

<bodyonload="window_onload();"onbeforeunload="return window_onbeforeunload()">

对toolbar的Click事件的响应函数名称统一规定为toolbar_onclick(evt)。比如:

function toolbar_onclik(evt)

{

switch(evt.ID)

{

case "Add":

f_addProcessDef(true);

break;

case "Remove":

f_removeProcessDef(true);

break;

default:

break;

}

}

普通的函数考虑使用f_前缀。使用f_前缀的原因是在微软提供的一些HTC中,使用了这一风格,当把函数指针作为參数传递时,使用f_作为前缀。代码显得比較清晰。

可是对于特定的函数,不是用此命名方法。比如:window_onload等。

比如:

function f_add()

{

var cellArray = oRow.cells;

var oRow = oTable.rows[0];

}

function window_onload()

{

}

function document_onkeydown()

{

}

function window_onbeforeunload()

{

}

变量的命名,假设是数组,考虑使用Array作为后缀,比如:

var cellArray = oRow.cells;

var itemArray = new Array();

假设变量是对象。考虑使用o作为前缀。

比如:

var oRow = oTable.rows[0];

JavaScript中,循环所的写法例如以下,不使用for … in的语法:

var arrayLength = itemArray.length;

for(var i=0; i<arrayLength; i++)

{

for(var j=0; j<100; j++)

{

//do someting ...

}

}

在须要弹出对话框的页面的头部加入例如以下语句:

var dialogBoxUrl = "../DialogBox.aspx";

在须要弹出对话框时,例如以下处理:

function f_search(callByMenu)

{

var dialogBoxFeature = "dialogWidth:400px; dialogHeight:250px; resizable:yes;";

var pageTitle = "查找任务";

var pageUrl = "WfAdmin/AssignmentSearchInfoInput.aspx";

var rtnValue = showDialogBox(dialogBoxUrl, pageUrl, pageTitle, dialogBoxFeature);

}

每一个文件头部都应该有凝视。用来描写叙述作者、最后改动时间、相关描写叙述、改动记录等。

/*

*

作       者: xxxx xxx xxx

最后改动时间: xxxx年x月xx日

描        述: xxxxxxxxxxxxxxxxxxxxxxxx

更新纪录:

1、  xxxx年x月xx日。改动人xxx。添加功能包含:xxxxx

*

*/

在全部为Public修饰符的方法都要加入凝视。

凝视包括Summary和Remark两部分,Summary部份是必需的,Remark部份可选。方法的凝视,还应该包括參数的凝视,返回值的凝视。

假设你确定你抛出的异常列表。就把所抛出异常的凝视加上。

比如:

///<summary>

///简要凝视文本

///</summary>

///<remarks>

///具体凝视文本

///</remarks>

public void F()

{

}

4.2.1   
 

样例:

public
void F1()

{

// ...

}

public
void F2()

{

// ...

}

原因

就像文章要分段一样。这样便于阅读。

样例

public
void F1()

{

if(condition)

{

//...

}

return
this; //返回语句之前加一空行

}

例外:

除非该函数过于简单,比方仅仅有一两条语句。

使用花括号进行段落划分可以指定方法内的变量的生命区域,从而使得代码更少出现一些由于不小心或者拼写错误导致的Bug。

比如:

public void F()

{

//段落 1

{

int i;

}

//段落 2

{

int j, k;

}

}

要独占一行

关于花括号的放置方法有非常多风格,争论也有非常长时间了。但我们坚持觉得,单独放置更明显一点。查找和配对也更直接。

第二种流行的风格是将左花括号和前面的语句放在一行。这样代码更紧凑,尤其是当花括号里的语句不多时更明显。

这样的风格源于杂志和书籍在排版时的美观要求,作为编程者。我们看问题的角度与排版不尽一致。

样例:

if(saaa)

{

}

//这样的方式表达空循环不够清楚

for(int i=0; i<TIMEOUT; i++);

//即使是空循环,也保留{},这样就清楚多了。

for(int i=0; i<TIMEOUT; i++)

{

}

样例:

//两条语句放在一行

if(buffer.Empty) status = ERROR_EMPTY;

//这样要清晰一些

if(buffer.Empty)

{

status = ERROR_EMPTY;

}

原因:

简化一行,清晰好读。

便于统计工具计算代码行数。

合并多条语句于一行没有明显的优点。

某些语句过长,不易于阅读,能够採用分行的办法。

语句的分行

在程序中嵌入Sql语句时,使用Sql分行使得代码更easy阅读。

比如

strSql = @"

SELECT Name, PwdHash, [Builtin], Description

FROM Hrms_Users

Where Id = ?

";

推断表达式的分行

if推断表达式多于一个的时候,採用分行编写。easy阅读。而且方便编写凝视。

比如:

if((dt !=
null) // 不为空值

&& (dt.Rows.Count != 0) //
而且数量不为0

)

{

//do something.....

}

在调用參数较为复杂的方法时。採用分行编写。easy阅读。

而且方便编写凝视。

比如:

db.RunSelectCommand(

sql,

DbUtils.MakeGuidInParam("@Id", entryID),

out dt

);

当一个方法的參数过多时。建议採用分行的写法。

比如:

public
void RunSelectCommand(

string commandString,

out DataTable dataTable,

int pageIndex,

int pageSize

)

{

}


參考.net framework类库。System.Web.UI.Control

版权声明:本文博客原创文章,博客,未经同意,不得转载。

05-11 15:16