C#语言上位机研发代码编写规范

Posted 自动化电气系统

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#语言上位机研发代码编写规范相关的知识,希望对你有一定的参考价值。

C#语言上位机研发代码编写规范 

 



 

 

 

目   录

1. 目的

2. 范围

3. 规范内容

3.1 文件规范

3.1.1 文件命名

3.1.2  文件内容格式

3.2 代码格式

3.2. 注释(Comment)规范

3.2.1. 模块(类)注释规范

3.2.2. 类属性注释规范

3.2.3. 方法注释规范

3.2.4. 代码间注释规范

3.3. 命名规范概述

3.3.1. 概述

3.4. 变量(Variable)命名规范

3.3.1. 程序文件(*.cs)中的变量命名规则

3.3.2. 控件命名规则

3.5. 常量命名规范

3.6. 类(Class)命名规范

3.7. 接口(Interface)命名规范

3.8. 方法(Method)命名规范

3.9. 命名空间(NameSpace)命名规范

3.10. 结构体命名

3.11. 文件命名规范

4. C# 编码基本要求

4.1. 程序结构要求

4.2. 可读性要求

4.3. 结构化要求

4.4. 正确性与容错性要求

4.5. 可重用性要求

5. 编程准则

5.1. 变量使用规范

5.2. 数据库操作规范

5.3. 对象使用规范

5.4. 模块设计原则

6. 编程参考

附录1C#关键字

附录2:主要名词/动词汉英对照表

附录3:常用缩写

 

1. 目的

编制此程序编码规范的目的是为了保证企业编写出的程序都符合相同的规范,保证一致性。

编码规范对于程序员而言尤为重要,有以下几个原因:

n  一个软件的生命周期中,80%的花费在于维护;

n  几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护;

n  编码规范可以改善软件的可读性,可以让程序员尽快而彻底地理解新的代码;

n  如果你将源码作为产品发布,就需要确认它是否被很好的打包并且清晰无误,一如你已经开发的其它任何产品;

为了执行规范,每个软件开发人员必须一致遵守编码规范。

2. 范围

适用于企业所有基于C#.NET平台的软件开发工作。

3. 规范内容

3.1 文件规范

3.1.1 文件命名

与类名名称相同

3.1.2  文件内容格式

开头注释

引用

命名空间

类体

变量(代理事件):用#region 变量………#endregion包括

属性:用#region属性………#endregion包括

构造:

方法(事件的实现):用#region方法………#endregion包括

3.2 代码格式

1、所有的缩进为4个空格,以空格代替Tab

2、在代码中垂直对齐左括号和右括号。

if(x==0)

              {

                   Response.Write("用户编号必须输入!");

              }

 不允许以下情况:

if(x==0) {

                Response.Write("用户编号必须输入!");

              }

或者:

if(x==0){Response.Write("用户编号必须输入!");}

3、为了防止在阅读代码时不得不滚动源代码编辑器,每行代码或注释在1024*800的显示频率下不得超过一显示屏。

4、当一行被分为几行时,通过将串联运算符放在每一行的末尾而不是开头,清楚地表示没有后面的行是不完整的。

5、每一行上放置的语句避免超过一条。

6、在大多数运算符之前和之后使用空格,这样做时不会改变代码的意图却可以使代码容易阅读。

例:

 int j = i+ k;

而不应写为

 int j=i+k;

7、将大的复杂代码节分为较小的、易于理解的模块。

8、编写 SQL 语句时,对于关键字使用全部大写,对于数据库元素(如表、列和视图)使用大小写混合。

9、将每个主要的SQL子句放在不同的行上,这样更容易阅读和编辑语句,

例如:  SELECT FirstName, LastName

FROM Customer

WHERE State = 'WA'

3.2. 注释(Comment)规范

注释规范包括:模块(类)注释规范、类的属性、方法注释规范、代码间注释

3.2.1. 模块(类)注释规范

模块开始必须以以下形式书写模块注释:

///<summary>

///模块编号:<模块编号,可以引用系统设计中的模块编号>(可选)

///功能说明:<对此类的描述,可以引用系统设计中的描述>

///编写日期:<模块创建日期,格式:YYYY-MM-DD>

///</summary>

如果模块有修改,则每次修改必须添加以下注释:

///<summary>

///Log编号:<Log编号,1开始一次增加>

///修改描述:<对此修改的描述>

///修改日期:<模块修改日期,格式:YYYY-MM-DD>

///</summary>

3.2.2. 类属性注释规范

在类的属性必须以以下格式编写属性注释:

///<summary>

///属性说明

///</summary>

3.2.3. 方法注释规范

在类的方法声明前必须以以下格式编写注释

/// <summary>

/// 说明:<对该方法的说明>

/// </summary>

/// <param name="<参数名称>"><参数说明></param>

/// <returns>

///<对方法返回值的说明,该说明必须明确说明返回的值代表什么含义>

/// </returns>

3.2.4. 代码间注释规范

代码间注释分为单行注释和多行注释:

单行注释://<单行注释>

多行注释:

/*多行注释1

              多行注释2

              多行注释3*/

代码中遇到语句块时必须添加注释(if,for,foreach,……),添加的注释必须能够说明此语句块的作用和实现手段(所用算法等等)。

3.3. 命名规范概述

3.3.1. 概述

1、必须使用语标准英文单词,不允许使用中文拼音。

2、如果有名词,必须使用单数形式。

3、使用大小写混合格式,将连接的几个单词首字母大写。

4、必须在330个字母以内。

5、如果使用缩写,必须使用本规范附录的缩写范例。

3.4. 变量(Variable)命名规范

具体例程:

 

BOOL类型    bEnable;

sz  char     szText

sb  sbyte     sbText

bt   byte     btText

n    int      nText

ui   uint      uiText

l    long     lText

ul   ulong    ulText

f    float     fText

d   double    dText

b   bool      bText

de  decimal   deText

str  string     strText

x,y  坐标

att  表属性

m_  类成员变量 m_nVal, m_bFlag

s_  类静态成员变量 s_nVal,s_bFlag

3.3.1. 程序文(*.cs)中的变量命名规则

程序中变量名称 = 变量的前缀 +代表变量含意的英文单词或单词缩写。

1.类模块级的成员变量请用“m_”作前缀

public class hello

{

        private string m_Name;

        private DateTime m_Date;

}

 

2.类的属性所对应的变量,采用属性名前加“m_”前缀的形式

public class hello

{

private stringm_Name;

public stringName

{

get

{

return m_Name;

}

}

}

3.过程级的变量不使用前缀

public class hello

{

void say()

{

string SayWord;

}

}

 

补充说明:

 

       针对异常捕获过程中的Exception变量命名,在没有冲突的情况下,统一命名为e

 

如果有冲突的情况下,重复加e,比如:ee

Try

{

//your code

try

{

//code

}

catch(Exceptionee)

{

//your code

}

}

catch(Exception e)

{

//your code

}

补充:如果捕获异常不需要作任何处理,则不需要定义Exception实例

例:

try

{

//your code

}

catch( Exception )

{

}

5.鉴于大多数名称都是通过连接若干单词构造的,请使用大小写混合的格式以简化它们的阅读。每个单词的第一个字母都是大写.

6.即使对于可能仅出现在几个代码行中的生存期很短的变量,仍然使用有意义的名称。仅对于短循环索引使用单字母变量名,如 i j

7.在变量名中使用互补对,如 min/maxbegin/end open/close

8.不要使用原义数字或原义字符串,如 For i = 1 To 7。而是使用命名常数,如 For i = 1 To NUM_DAYS_IN_WEEK 以便于维护和理解。

3.3.2. 控件命名规则

控件命名 =  Web控件缩写前缀 + 变量名

下表为常用控件缩写前缀:

控件

缩写

Label

lbl

TextBox

txt

CheckBox

chk

Button

cmd

ListBox

lst

DropDownList

drp

等等


 

3.5. 常量命名规范

常量名也应当有一定的意义,格式为 NOUN NOUN_VERB。常量名均为大写,字之间用下划线分隔。

例:

       private const bool  WEB_ENABLEPAGECACHE_DEFAULT =  true;

       private const int   WEB_PAGECACHEEXPIRESINSECONDS_DEFAULT = 3600;

       private const bool  WEB_ENABLESSL_DEFAULT =  false;

注:

变量名和常量名最多可以包含255 个字符,但是,超过 25 30 个字符的名称比较笨拙。此外,要想取一个有实际意义的名称,清楚地表达变量或常量的用途,2530个字符应当足够了。

3.6. 类(Class)命名规范

1、名字应该能够标识事物的特性。

2、名字尽量不使用缩写,除非它是众所周知的。

3、名字可以有两个或三个单词组成,但通常不应多于三个。

4、在名字中,所有单词第一个字母大写。

   例如:IsSuperUser,包含ID的,ID全部大写,如CustomerID

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

6、少用缩写。

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

例:

public class FileStream

public class Button

public class String

3.7. 接口(Interface)命名规范

和类命名规范相同,唯一区别是  接口在名字前加上“I”前缀

例:

   interface IDBCommand;

   interface IButton;

3.8. 方法(Method)命名规范

和类命名规范相同。

3.9. 命名空间(NameSpace)命名规范

和类命名规范相同。

3.10. 结构体命名

结构体类型命名必须全部用大写字母,原则上前面以下划线开始;结构体变量命名必须用

大小写字母组合,第一个字母必须使用大写字母,必要时可用下划线间隔。对于私有数

据区,必须注明其所属的进程。全局数据定义只需注意其用途。

示例如下:

typedef struct

{

charszProductName[20];

charszAuthor[20];

charszReleaseDate[16];

charszVersion[10];

unsigned longMaxTables;

unsigned longUsedTables;

}DBS_DATABASE;

 

DBS_DATABASE GdataBase;

3.11. 文件命名规范

1、文件命名采用主谓结构,首字母大写。

2、文件和文件夹的名称应该精确地说明它们的用途。

4. C# 编码基本要求

4.1. 程序结构要求

1、程序结构清晰,简单易懂,单个函数的程序行数不得超过100行。

2、打算干什么,要简单,直接了当,代码精简,避免垃圾程序。

3、尽量使用.NET库函数和公共函数(无特殊情况不要使用外部方法调用windows的核心动态链接库)。

4、不要随意定义全局变量,尽量使用局部变量。

4.2. 可读性要求

1、可读性第一,效率第二(代码是给人读的J)。

2、保持注释与代码完全一致。

3、每个源程序文件,都有文件头说明,说明规格见规范。

4、每个函数,都有函数头说明,说明规格见规范。

5、主要变量(结构、联合、类或对象)定义或引用时,注释能反映其含义。

6、处理过程的每个阶段都有相关注释说明。

7、在典型算法前都有注释, 同时算法在满足要求的情况下尽可能简单。

8、利用缩进来显示程序的逻辑结构,缩进量一致并以Tab键为单位,定义Tab为 6个字节。

9、循环、分支层次不要超过五层。

10、注释可以与语句在同一行,也可以在上行。

11、空行和空白字符也是一种特殊注释。

12、一目了然的语句不加注释。

13、注释的作用范围可以为:定义、引用、条件分支以及一段代码。

14、注释行数(不包括程序头和函数头说明部份)应占总行数的 1/5 到 1/3

15、常量定义(DEFINE)有相应说明。

4.3. 结构化要求

1、禁止出现两条等价的支路。

2、禁止GOTO语句。

3、用 IF 语句来强调只执行两组语句中的一组。禁止 ELSE GOTO 和 ELSE RETURN。

4、用 CASE 实现多路分支。

5、避免从循环引出多个出口。

6、函数只有一个出口。

7、不使用条件赋值语句。

8、避免不必要的分支。

9、不要轻易用条件分支去替换逻辑表达式。

4.4. 正确性与容错性要求

1、程序首先是正确,其次是优美

2、无法证明你的程序没有错误,因此在编写完一段程序后,应先回头检查。

3、改一个错误时可能产生新的错误,因此在修改前首先考虑对其它程序的影响。

4、所有变量在调用前必须被初始化。

5、对所有的用户输入,必须进行合法性检查。

6、不要比较浮点数的相等,如: 10.0 * 0.1 == 1.0 ,不可靠

7、程序与环境或状态发生关系时,必须主动去处理发生的意外事件,如文件能否逻辑锁定、打印机是否联机等,对于明确的错误,要有明确的容错代码提示用户。

8、单元测试也是编程的一部份,提交联调测试的程序必须通过单元测试。

9、尽量使用规范的容错语句.

  例如:

try

{

}

catch

{

}

finally

{

}

4.5. 可重用性要求

1、重复使用的完成相对独立功能的算法或代码应抽象为asp.net服务或类。

2、asp.net服务或类应考虑OO思想,减少外界联系,考虑独立性或封装性。

5. 编程准则

5.1. 变量使用规范

1、不允许随意定义全局变量。

2、一个变量只能有一个用途;变量的用途必须和变量的名称保持一致。

3、所有变量都必须在类和函数最前面定义,并分类排列。

5.2. 数据库操作规范

1、查找数据库表或视图时,只能取出确实需要的那些字段。

2、使用无关子查询,而不要使用关联子查询。

3、清楚明白地使用列名,而不能使用列的序号。

5.3. 对象使用规范

1、尽可能晚地创建对象,并且尽可能早地释放它。

5.4. 模块设计原则

1、不允许随意定义公用的函数和类。

2、函数功能单一,不允许一个函数实现两个及两个以上的功能。

3、不能在函数内部使用全局变量,如要使用全局变量,应转化为局部变量。

4、函数与函数之间只允许存在包含关系,而不允许存在交叉关系。即两者之间只存在单方向的调用与被调用,不存在双向的调用与被调用。

6. 编程参考

1.  避免将多个类放在一个文件里面。

2.  一个文件应该只有一个命名空间,避免将多个命名空间放在同一个文件里面。

3.  一个文件最好不要超过500行的代码(不包括机器产生的代码)。

4.  一个方法的代码长度最好不要超过25行。

5.  避免方法中有超过5个参数的情况。使用结构来传递多个参数。

6.  每行代码不要超过80个字符。

7.  不要手工的修改机器产生的代码。

a)  如果需要编辑机器产生的代码,编辑格式和风格要符合该编码标准。

b)  Use partialclasses whenever possible to factor out the maintained portions.

8.  避免利用注释解释显而易见的代码。

a)  代码应该可以自解释。好的代码由可读的变量和方法命名因此不需要注释。

9.  Document only operational assumptions,algorithm insights and so on.  

10.  避免使用方法级的文档。

a)  使用扩展的API文档说明之。

b)  只有在该方法需要被其他的开发者使用的时候才使用方法级的注释。(在C#中就是///)

11.  不要硬编码数字的值,总是使用构造函数设定其值。

12.  只有是自然结构才能直接使用const,比如一个星期的天数。

13.  避免在只读的变量上使用const。如果想实现只读,可以直接使用readonly。

public class MyClass

{

   public readonly int Number;

   public MyClass(int  someValue)

   {

      Number = someValue;

   }

   public const int  DaysInWeek = 7;

}

14.  每个假设必须使用Assert检查

a)  平均每15行要有一次检查(Assert)

using System.Diagnostics;

object GetObject()

{…}

object obj = GetObject();

Debug.Assert(obj != null);

15.  代码的每一行都应该通过白盒方式的测试。

16.  只抛出已经显示处理的异常。

17.  在捕获(catch)语句的抛出异常子句中(throw),总是抛出原始异常维护原始错误的堆栈分配。

catch(Exceptionexception)

{   

   MessageBox.Show(exception.Message);

   throw ; //和throw exception一样。

}

18.  避免方法的返回值是错误代码。

19.  尽量避免定义自定义异常类。

20.  当需要定义自定义的异常时:

a)  自定义异常要继承于ApplicationException。

b)  提供自定义的序列化功能。

21.  避免在单个程序集里使用多个Main方法。

22.  只对外公布必要的操作,其他的则为internal。

23.  Avoid friend assemblies, as it increasesinter-assembly coupling.

24.  Avoid code that relies on an assembly runningfrom a particular location.

25.  使应用程序集尽量为最小化代码(EXE客户程序)。使用类库来替换包含的商务逻辑。

26.  避免给枚举变量提供显式的值。

//正确方法 

public enum Color

{   

   Red,Green,Blue

}

//避免

public enum Color

{   

   Red = 1,Green=  2,Blue = 3

}

27.  避免指定特殊类型的枚举变量。

//避免 

public enumColor  : long

{   

   Red,Green,Blue

}

28.  即使if语句只有一句,也要将if语句的内容用大括号扩起来。

29.  避免使用trinary条件操作符。

30.  避免在条件语句中调用返回bool值的函数。可以使用局部变量并检查这些局部变量。

boolIsEverythingOK()

{…}

//避免

if (IsEverythingOK())

{…}

//替换方案 

bool ok =IsEverythingOK();

if (ok)

{…}

31.  总是使用基于0开始的数组。

32.  在循环中总是显式的初始化引用类型的数组。

public class MyClass

{}

MyClass[] array =new  MyClass[100];

for(int index = 0;index < array.Length;  index++)

{

   array[index] = new  MyClass();

}

33.  不要提供public 和 protected的成员变量,使用属性代替他们。

34.  避免在继承中使用new而使用override替换。

35.  在不是sealed的类中总是将public 和 protected的方法标记成virtual的。

36.  除非使用interop(COM+ 或其他的dll)代码否则不要使用不安全的代码(unsafe code)。

37.  避免显示的转换,使用as操作符进行兼容类型的转换。

Dog dog = newGermanShepherd();

GermanShepherdshepherd = dog  as  GermanShepherd;

if (shepherd != null)

{…}

38.  当类成员包括委托的时候

a) Copy a delegate to a local variable before publishing to avoidconcurrency race

condition. 

b)  在调用委托之前一定要检查它是否为null

public classMySource

{

   public event EventHandler  MyEvent;

   public void FireEvent()

   {

      EventHandler temp = MyEvent;

      if(temp != null )

      {

         temp(this,EventArgs.Empty);

      }

   }

}  

39.  不要提供公共的事件成员变量,使用事件访问器替换这些变量。

public classMySource

{

   MyDelegate m_SomeEvent ;

   public event MyDelegate SomeEvent

   {

      add

      {

         m_SomeEvent += value;

      }

      remove

      {

         m_SomeEvent -= value;

      }

   }

}

40.  使用一个事件帮助类来公布事件的定义。

41.  总是使用接口。

42.  类和接口中的方法和属性至少为2:1的比例。

43.  避免一个接口中只有一个成员。

44.  尽量使每个接口中包含3-5个成员。

45.  接口中的成员不应该超过20个。

a)  实际情况可能限制为12个

46.  避免接口成员中包含事件。

47.  避免使用抽象方法而使用接口替换。

48.  在类层次中显示接口。

49.  推荐使用显式的接口实现。

50.  从不假设一个类型兼容一个接口。Defensively query for that interface.

SomeType obj1;

IMyInterface obj2;

/* 假设已有代码初始化过obj1,接下来 */

obj2 = obj1 asIMyInterface;

if (obj2 != null)

{

   obj2.Method1();

}

else

{

   //处理错误

}  

51.  表现给最终用户的字符串不要使用硬编码而要使用资源文件替换之。

52.  不要硬编码可能更改的基于配置的字符串,比如连接字符串。

53.  当需要构建长的字符串的时候,使用StringBuilder不要使用string

54.  避免在结构里面提供方法。

a)  建议使用参数化构造函数

b)  可以重裁操作符

55.  总是要给静态变量提供静态构造函数。

56.  能使用早期绑定就不要使用后期绑定。

57.  使用应用程序的日志和跟踪。

58.  除非在不完全的switch语句中否则不要使用goto语句。

59.  在switch语句中总是要有default子句来显示信息(Assert)。

int number  = SomeMethod();

switch(number)

{

   case 1:

      Trace.WriteLine("Case 1:");

      break;

   case 2:

      Trace.WriteLine("Case 2:");

      break;

   default :

      Debug.Assert(false);

      break;

}

60.  除非在构造函数中调用其他构造函数否则不要使用this指针。

// 正确使用this的例子

public class MyClass

{

   public MyClass(string message )

   {}

   public MyClass()  : this("hello")

   {}

}

61.  除非你想重写子类中存在名称冲突的成员或者调用基类的构造函数否则不要使用base来访问基类的成员。

// 正确使用base的例子

public class Dog

{

   public Dog(string name)

   {}

   virtual public void Bark( int howLong)

   {}

}

public classGermanShepherd : Dog

{

   public GermanShe pherd(string name): base(name)

   {}

   override public void Bark(int  howLong) 

   {

      base .Bark(howLong);  

   }

}

62.  基于模板的时候要实现Dispose()和Finalize()两个方法。

63.  通常情况下避免有从System.Object转换来和由System.Object转换去的代码,而使用强制转换或者as操作符替换。

class SomeClass

{}

//避免:

classMyClass<T> 

{   

   void SomeMethod(T t)    

   {

      object temp = t;      

      SomeClass obj = (SomeClass)temp;    

   }

}

// 正确:

classMyClass<T> where T : SomeClass

{   

   void SomeMethod(T t)   

   {

      SomeClass obj = t;   

   }

}

64.  在一般情况下不要定影有限制符的接口。接口的限制级别通常可以用强类型来替换之。

public classCustomer

{…}

//避免:

public interfaceIList<T> where T : Customer 

{…}

//正确:

public interfaceICustomerList : IList<Customer> 

{…}

65.  不确定在接口内的具体方法的限制条件。

66.  总是选择使用C#内置(一般的generics)的数据结构。

附录1C#关键字

关键字是系统预定义的保留字,编译器在扫描源程序时,遇到关键字将作出专门的解释负责执行特定的任务,我们也可以认为关键字是语句的一部分,我们不能用关键字来定义各种类型的名称。不过,C#允许我们使用关键字前面符号@来作为自定义的名称,比如,我们不允许采用as,但可以采用@as来作为一个变量声明的名称,下面列出了C#中定义的关键字:

Abstract

as

enum

event

long

namespace

stackalloc

static

base

Explicit

new

string

bool

break

extern

false

null

object

struct

switch

byte

Finally

Operator

this

case

catch

fixed

float

out

override

throw

true

char

For

params

try

checked

class

foreach

goto

private

protected

typeof

uint

const

If

public

ulong

continue

decimal

implicit

in

readonly

ref

unchecked

unsafe

default

Int

return

ushort

delegate

do

interface

internal

sbyte

sealed

using

virtual

double

is

short

void

else

lock

sizeof

while

 

附录2:主要名词/动词汉英对照表

    附件                Attach

    一览                List

    详细                Detail

    编辑                Edit

    修改                Modify

    变更                Alter

附录3:常用缩写

    arr             array(数组)

    bg              background(背景)

    cate                category(种类)

    corp                corporation(公司)

    func                function(函数)

    gov             government(政府)

    img             image(图像)

    inc             include(包括、包含)

    info                information(信息)

    max             Minimum(最小值)

    min             Maximum(最大值)

    msg             message(消息)

    num             Number(数目)

    No              Number(号码)

    pic             picture(图像)

    proj                project(工程)

    pwd             password(密码、口令)

    subj                subject(主题)

    sys             system(系统)


以上是关于C#语言上位机研发代码编写规范的主要内容,如果未能解决你的问题,请参考以下文章

C#编写上位机连接华为云平台IoTDA

c#上位机开发

C#编写Modbus协议加速度传感器上位机

C#编写上位机驱动运动控制板卡

C#编写上位机使用UDP给单片机发送Json格式数据

C#编写上位机使用UDP给单片机发送Json格式数据(完整程序)