C#编码规范

    技术2022-05-11  70

    1          关于C#编码规范

    这个文档可以作为一个向导,以写强壮可靠的程序。虽然这里关注的是用C#写程序,但如果使用另外一种编程语言,很多规则和原理也是有用的。

    2          文件组织

    2.1      C#源文件

    把每个类都放在单独的文件中,文件名字和类名一致(用.CS作为扩展名)。类文件不要太长,不要超过2000LOC。必要时,分割代码,使结构更清晰。

    2.2      目录安排

    为每个命名空间创建一个目录(如,对于MyProject.TestSuite.TestTier使用MyProject/TestSuite/TestTier作为路径,不要使用带“.”的命名空间)。这样更易于映射命名空间到目录。

    3          缩进

    3.1      分行

    如果表达式不适合单行显示,应根据下面通常的原则分行:

    n         在一个逗号后换行

    n         在一个操作符后换行

    n         在表达式的高层次处换行

    n         新行与前一行在同一层次,并与表达式的起始对齐

    方法分行的例子:

    long MethodCall(expr1, expr2,

                            expr3, expr4, expr5);

    算术表达式分行的例子:

    好的:

           var = a * b / (c – g + f) +

                   4 * z;

    坏的风格,要避免:

           var = a * b / (c – g +

                   f) + 4 * z;

    第一个是好的,因为分行符合高层次规则。

    3.2      空白

    不要使用空格缩进 使用tabs

    4          注释

    4.1      块注释

    通常要避免块注释,而使用C#标准的///注释来描述。如果希望使用块注释,应该使用下面的风格:

    / * Line 1

      * Line 2

      * Line 3

      */

    块注释很少使用,通常是用来注释掉大块的代码。

    4.2      单行注释

    应该使用//注释掉一行代码,也可以用它注释掉代码块。当单行注释用来做代码解释时,必须要缩进到与代码对齐。

    4.3      文档注释

    单行XML注释的形式如下:

    /// <summary>

    /// This class…

    /// </summary>

    多行XML注释的形式如下:

    /// <exception cref=”BogusException”>

    /// This exception gets thrown as soon as a

    /// Bogus flag gets set.

    /// </exception>

    5          声明

    5.1      每行声明的数量

    建议每行只有一个声明,还方便注释,如:

    int level;  // indentation level

    int size;   // size of table

    变量的命名意义要明确。如果能够自解释,如indentLevel,就不用注释。

    不好的:

    int a, b; // What is ‘a’? What does ‘b’ stand for?

    5.2      初始化

    尽量在局部变量声明时进行初始化,例如:

    string name = myObject.Name;

    int val = time.Hours;

    注意:初始化对话框时,尽量使用语句:

    Using (OpenFileDialog openFileDialog = new OpenFileDialog())

    {

           ……

    }

    5.3      类和接口的声明

    当写C#类和接口时,应按照下面的格式规则:

    n         在方法名字和参数列表的起始括号“(”之间没有空格

    n         开括号“{”应出现在声明语句之后的下一行

    n         闭括号“}”自己占一行,并缩进到对应的开括号位置

    例如:

    class MySample : MyClass, IMyInterface

    {

    int myInt;

     

    public MySample(int myInt)

    {

           this.myInt = myInt;

    }

     

    void Inc()

    {

           ++myInt;

    }

     

    void EmptyMethod()

    {

    }

    }

    6          语句

    6.1      简单语句

    每行应该只包含一个语句。

    6.2      返回语句

    返回语句不应该带有最外面的括号。

    不应该使用:

    return (n * (n + 1) / 2);

    应该使用:

    return n * (n + 1) / 2;

    6.3      If, if - else, if else - if else语句

    if, if – elseif else – if else语句应该按照下面格式:

    if (condition)

    {

           ……

    }

     

    if (condition)

    {

           ……

    }

    else

    {

           ……

    }

     

    if (condition)

    {

        ……

    }

    else if (condition)

    {

        ……

    }

    else

    {

        ……

    }

    注意:即使某条件下只有一个语句,也要使用大括号“{”“}”。后面的循环等语句也一样。

    6.4      for / foreach语句

    for语句形式如下:

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

    {

        ……

    }

    或者使用单行形式:

    for (initialization; condition; updat);

    单行形式可考虑使用while语句代替。

    foreach语句如下:

    foreach (int i in intList)

    {

        ……

    }

    6.5      while / do – while语句

    while语句如下:

    while (condition)

    {

        ……

    }

    空的while语句形式如下:

    while (condition);

    do – while语句如下:

    do

    {

        ……

    }

    while (condition);

    6.6      switch语句

    switch语句形式如下:

    switch (condition)

    {

        case A :

               ……

               break;

        case B :

               ……

               break;

        default :

               ……

               break;

    }

    6.7      try – catch语句

    try – catch语句形式如下:

    try

    {

        ……

    }

    catch (Exception e)

    {

        ……

    }

    或者

    try

    {

        ……

    }

    catch (Exception e)

    {

        ……

    }

    finally

    {

        ……

    }

    6.8      属性

    属性形式如下:

    public string Name

    {

        get

          {

                  ……

          }

          set

          {

                  ……

          }

    }

    对于抽象属性:

    public string Name

    {

        get;

        set;

    }

    6.9      枚举

    枚举形式如下:

    public enum Color

    {

        Red,

        Green,

        Blue

    }

    7          空白

    7.1      空行

    使用空行按照逻辑关系分隔代码,能提高可读性。

    在下面元素之间要使用一个空行:

    n         构造函数

    n         属性

    n         方法

    n         方法内的逻辑块

    7.2      内部空格

    在逗号或分号之后应该有一个空格,例如:

    应该使用:

           TestMethod(a, b, c);

    不应该使用:

           TestMethod(a,b,c);或者TestMethod( a, b, c );

    操作符两边要有一个空格(递增和逻辑否等一元操作符除外),例如:

    应该使用:

           a = b;

    不应该使用:

           a=b;

    应该使用:

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

    不应该使用:

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

    7.3      制表格式

    行逻辑块应该写成类似表格格式:

    string   name         = “Mr. Ed”;

    int       myValue     = 5;

    Test     aTest         = Test.TestYou;

    8          命名约定

    8.1      大写风格

    8.1.1        Pascal风格

    大写每一个单词的第一个字符,如TestCounter

    8.1.2        Camel风格

    除了第一个单词,大写其它单词的第一个字符,如testCounter

    8.1.3        全部大写

    如果一个标志符是只包含123个字符的缩写,可以全部大写,例如:

    public class Math

    {

        public const double PI = ......

    }

    8.2      命名规则

    .Net中,通常认为使用下划线和匈牙利符号命名是不好的。

    匈牙利符号定义了一组名字的前缀和后缀,来表示变量的类型。这种命名风格在早期的windows编程中广泛使用。在MFC编程中,还习惯使用m_作为成员变量的前缀。这些风格在.Net中不应该使用。记住:一个好的变量名字应该描述语义,而不是类型。

    GUI代码是个例外。所有GUI元素类型(如Button)的域和变量名字,应该以它的类型全名作为后缀,例如:

    System.Windows.Forms.Button       cancelButton;

    System.Windows.Forms.TextBox      nameTextBox;

    8.2.1        classstructnamespace命名规则

    n         名字必须是名词或名词短语

    n         异常类要以Exception作为后缀

    n         不要使用任何前缀

    n         使用Pascal风格

    8.2.2        interface命名规则

    n         用名词,名词短语或者描述行为的形容词命名接口。(如IComponentIEnumbetable

    n         使用Pascal风格

    n         使用I作为名字的前缀,I后面的字符(接口名字的第一个字符)要大写

    8.2.3        enum命名规则

    n         枚举类型名和值的名字都使用Pascal风格

    n         枚举类型和值都没有前缀和后缀

    8.2.4        域命名规则

    n         使用描述性的名字,能充分表示出变量的含义

    n         对于静态的readonlyconst域,用名词,名词短语或名词缩写命名

    n         public域使用Pascal风格

    n         protectedprivate域使用Camel风格

    8.2.5        参数命名规则

    n         使用描述性的名字,能充分表示出变量的含义

    n         使用Camel风格

    8.2.6        变量命名规则

    n         尽量使用含义明确的名字

    n         如果变量仅用来在循环中计数,应优先使用ijklmn

    n         使用Camel风格

    8.2.7        方法命名规则

    n         用动词或动词短语命名

    n         使用Pascal风格

    8.2.8        属性命名规则

    n         使用名词或名词短语命名

    n         使用Pascal风格

    8.2.9        事件命名规则

    n         事件控制器要带有EventHandler后缀

    n         使用sendere命名两个参数

    n         事件参数类要带有EventArgs后缀

    n         考虑使用动词命名事件

    n         对于有“之前”或“之后”概念的事件,要使用现在时或过去时命名

    n         使用Pascal风格

    9          编程实践

    9.1      书写顺序

    书写类时,按照从上到下的顺序,类成员应该是域,构造函数,属性,方法。

    9.2      成员可视性

    类的域都应该是private,如果需要被外部访问,使用public属性进行访问。但也有例外:

    n         如果类的域仅作为一种数据集合,可以将域设定为public,这样的类不要有任何方法

    n         常量域,静态域或静态常量域可以设定为public

    private是默认的类成员访问修饰符,可以省略,但为了明确表达,应该书写出来。

    9.3      功能单一

    类的功能要单一,不要组合没有直接关联的功能。方法也一样。一个方法只完成一个任务,不要把多个任务组合进一个方法,即使那些任务很小。就是说,应该以逻辑功能来界分类或方法。

    9.4      使用枚举

    不要使用数字或字符串来指示离散值,应该使用枚举。

    不好的:

    void SendMail(string message, string mailType)

    {

    switch (mailType)

    {

    case "Html" :

            ……

            break;

    case "PlainText" :

            ……

            break;

    case "Attachment" :

            ……

            break;

    default :

            ……

            break;

    }

    }

    好的:

    enum MailType

    {

            Html,

            PlainText,

            Attachment

    }

     

    void SendMail(string message, MailType mailType)

    {

    switch (mailType)

    {

    case MailType.Html :

            ……

            break;

    case MailType.PlainText :

            ……

            break;

    case MailType.Attachment :

            ……

            break;

    default :

            ……

            break;

    }

    }

    9.5      捕获异常

    只捕获特定的异常,如读取外部文件,而不要捕获一般异常,有利于调试排错。

    不要捕获了异常却什么也不错,应该做适当处理,并把结果反馈到界面。如果隐藏了一个异常,将很难知道异常到底发生了没有,或者在哪里发生的。

     

    最新回复(0)