1.项目开发_C#代码编写规范

1.前言:  

  正所谓无规矩不成方圆,我们在开发软件的过程中通常都是多人协作的过程,这中间就涉及到沟通,如果在团队协作开发之前或者新成员加入之前对很多约定不是很清楚的话,那无疑会大大增加沟通的成本,所以我们必须要对这门编程语言和项目构成在编写上有一些约束和规定,让每个阅读过这个约定条例的成员很清晰的知道代码的意义;

2.描述:

  2.1:适用版本:

  本规范适用当前项目中所有使用到的语言

  2.2:应用范围:

  项目开发成员在新立项及老项目维护中新增和修改的代码必须严格按照此规范执行,包括代码review;

  2.3:约定变更:

  技术语言版本日新月异,我们的规范也不可能一成不变,在必要的时候会根据实际情况进行调整更新;

  2.4:拼写方法:

  规范中统一采用 “驼峰命名法” 和 “帕斯卡命名法” 及 “匈牙利命名法”

    1. 驼峰命名法(小驼峰命名法):aAaB
      • 通过大小写的区分使得复合词呈现”块状”(bump),后面看上去像是骆驼的驼峰(hump),这就是驼峰命名法的由来,小驼峰命名法通过 第一个词为小写,后面每个词首字母为大写便是小驼峰命名法,例如:成员变量 userName;
    2. 帕斯卡命名法(大驼峰命名法):AaBb
      • 帕斯卡命名法和小驼峰命名法是类似的,只是第一个词的首字母是大写后面的词首字母也是大写,所以我们也可以称呼他为大驼峰命名法,例如:转换String类型的方法命名 ToString();
    3. 匈牙利命名法:iAaBb
      • 匈牙利命名法呢其实和大驼峰命名法又比较类似只是通常在这个变量之前会加一个或者多个前缀来表示 类型,指针,等,例如:方法传参 iNumberOfShop 表示 int类型的商品数量;

3.命名:

  3.1 单词规范:

    1. 可读性比简短性重要;
    2. 命名必须由英文字母或英文字母+数字的方式组成,必须以字母开头,不得包含其它符号,(在作为临时变量的时候允许 “_”作为命名开头),另外注意CLR允许混合语言编程,因此不能仅通过大小写来区分命名,例如:test和 Test;
    3. 严禁使用含有人称化的单词来定义方法,变量,类型等,例如:my,me,we 等;
    4. 严禁使用单个字母表示变量,(循环变量除外);
    5. 尽量使用完成单词,除非一些约定熟成的英文缩写,如( department->dept,message->msg )等,不要随意创造缩写,防止协同人员无法看懂;

  3.2 名称空间:

    • 名称空间的使用需要使用using来引用,不能通过长引用访问;如 名称空间 Test.DAL下面的 UserTable 类中的 GetUserInfo() 方法的调用,例如:
 1 //应该使用下面这种方式访问调用
 2 using Test.DAL;
 3 static void Main(){
 4      var userDAL = new UserTable();
 5      userDAL.GetUserInfo();        
 6 }
 7 
 8 //不应该使用下面这类方式访问
 9 static void Main()
10 {
11      var userDAL=new Test.DAL.UserTable().GetUserInfo();
12 }

 

  3.3 类型,结构,接口,参数,变量,常量,枚举,方法和事件命名规范:

    • 成员变量和参数统一使用小驼峰命名法,成员变量(字段)采用下划线(”_”)开头,例如:
 1 public class Cut
 2 {
 3      //字段/变量命名      
 4      private string _cutName; 
 5      //参数命名
 6      public string GetCutName(string cutName)
 7      { 
 8              _cutName=cutName;
 9      }
10 }

 

    • 属性,方法均采用“帕斯卡命名法”:
      1.  单词(或者众所周知的缩写)只有两个字母则是特例,需要单词全部大写,例如,InputIO,IOStream 等;
      2. 布尔类型属性(及对应类型的成员变量)应该添加前缀Is,Can,Has,例如:IsFolder,CanRead,HasValue等;
      3. 方法的命名使用动词,属性的命名采用名词,两者要区分开来,例如:GetLength(动词)作为方法命名,使用Length(名词)作为属性命名;
    • 名称空间,类型,结构,和接口定义采用“帕斯卡命名法”:
      1. 一般情况下,要求类型,接口和接口的命名和文件名相同;

      2. 不要给类型和接口添加签证;

      3. 派生类建议以基类作为结尾,比如:PlainTextDocument:Document

      4. 接口一律添加 I 前缀,比如:IDocument

    • 枚举采用“帕斯卡命名法”:

      1. 使用单数形式命名一般枚举;
      2. 使用复数形式命名支持位域的枚举;
      3. 建议枚举都加上Enum作为前缀方便区分;
    • 常量全部采用大写的形式拼写,单词间采用下划线风格,例如:const string WEBSITE_NAME="工具人Johnny";
    • 事件和方法使用动词命名,事件还需使用现在时和过去时表示事件的前后概念;
      1. 事件对象本身不要添加含有“Event”的后缀;
      2. 事件处理方法(事件类型委托)需要添加“EventHandler”后缀,并且使用“sender”和“e”作为事件参数.例如:
1 public delegate void ClickedEventHandler(object sender,ClickedEventArgs e)
2 {
3        //to do something
4 }

        3.事件传递的参数需要附加后缀“EventArgs”,例如:

1 public class ClickedEventArgs:EventArgs
2 {
3       //do something      
4 }

4.要求:

  4.1 可读性:

    1. 任何方法,属性,枚举等等框架性结构定义之间必须仅且只能保持一行空行,成员变量定义之间无空行;
    2. 根据代码层次每次缩进一个层次且每层缩进两个空格(前端编码)和 四个空格(后端编码),同时避免使用非Visual Studio作为文本编辑器修改代码或者页面导致不同缩进字符数;
    3. 必须保证成对的大范围定义符号花括号"{"和“}”处于同一缩进层次;
    4. 每行代码都确保只有一个语句段,换句话说就是只包含一个语句分隔符";";
    5. 为确保VS窗口代码阅读的便利性,基于1024X768分辨率下将代码汇集到一个屏幕中,不要出现需要左右滑动的情况;超出屏幕的代码需要在适当的地方进行端行;
    6. 任何时候不要省略掉花括号;

  4.2 规范化和执行效率:

    1. 方法参数类型必须要具备真是意义:尽量不要使用弱类型,可变类型,或者通用类型等,例如:IID字段 使用 String字段类型进行传递,(绝大部分的IID的类型均为integer类型),总之就是比如 这个是一个前台和后台交互的方法,为了图简约全部设计传参类型为 String,实际上使用传参字段是需要Int,这样虽然方便但是会进行装箱操作,会损耗资源,积少成多,所以不被允许,此外因为参数都代表具体含义,所以不允许使用"匈牙利命名法"使其意义复杂;
    2. 可以复用的对象严禁实例化多次:在同一个方法,或者访问域中能够多次使用的类型的实例对象,必须第一次使用就实例化,严禁多次实例化,同时也要避免在开始就实例化,要放在使用的变量附近;
    3. 引用类型变量值严禁使用比较操作符:虽然目前.NET使用比较操作符("==",“>”,“<”)可以判断大部分引用类型,但是为了更加规范化和避免出错的可能,规定必须使用Equals,代替 “==”判断引用类型是否相等,同时也禁止使用“ ”表示空串,应该使用String.Empty;
    4. 字符串连接的优化:如果字符串需要进行3次及以上的拼接,需要使用StringBuilder对象的Append()方法进行拼接,如果是在字符串初始化的时候可以直接使用“+”,因为VC#的编译器已经对其进行了优化;
    5. 重复代码执行效率优化:对于短时间内重复执行的代码,例如(for/while等循环代码块或者递归调用)内严禁直接访问共享性非托管资源,(典型如:数据库连接对象,服务器磁盘IO对象),比如需要对一个数据列表读取子表内容,不要通过for来进行一次一次的访问连接字串每次读取,应该将数据列表中的键先便利出来,再通过一次 MainId in ('','')来一次读取,读取到缓存中再进行操作,此举是避免某个时间段内单个用户操作大量占用稀缺资源导致系统瓶颈;
    6. 代码强壮性要求:常见的错误是“未将代码引用对象实例”,"无效的引用",原因是对象没有实例化或者值为Null的情况下使用了此对象的属性,方法等成员,因此规定任何代码在对象实例化之前,必须在代码中考虑异常处理,除非明确知道该对象不会存在“无效引用”等情况,此外一般都需要在参数入口处第一时间检测代合法性,并且针对不同情况进行处理,类似代码中不仅要考虑正常流程还需要考虑异常流程;要尽量确保代码在执行过程中的任何情况都由对应的处理;
    7. 资源释放:对于实现了IDisposable接口类型的引用,必须通过using块进行显示资源释放,不建议自行实现析构方法,如果实在需要使用就必须调用GC.GC.SuppressFinalize来阻止CLR再调用析构方法;

  4.3 异常:

    1. 目前异常的使用在大部分程序员开发的.NET项目中都是比较薄弱的环节,因此强制规定下述规则
    2. 错误信息必须以异常对象返回/抛出:如果代码中产生错误,需要中断代码执行返回调用者,必须以异常对象Exception及其继承类型的方式进行抛出,严禁通过出口参数和返回参数返回异常代码的一部分;
    3. 避免随意“吃掉/屏蔽”异常:严格规定在非特殊情况下(异常需要显示的利用且不影响代码的正常执行),异常必须层层抛出直至最顶层的调用者,不应该被调用的中间环节截留,即使调用层次中需要记录日志,必须要在使用完后重新抛出,最终如何决定异常处理需要最顶层决定;
    4. 尽量避免大异常捕捉:通常大部分人员在写逻辑方法的时候会整个将方法try catch,无法在最小范围内捕捉异常,无法在异常返回中知道异常详细情况,所以需要在小范围块中进行专项异常捕捉;

  4.4 变量和属性(Property):

    1. 强制规定:类型(类和结构)的成员变量必须定义为私有存取范围,若是需要被类的外部访问,必须通过定义公有(public)或者 受保护(protected)存取范围的属性(Property),从而不会将成员直接暴露在类型外部;

  4.5 初始化:

    1. 强制规定:如果代码的返回值不能为String.Empty,String类型的返回值必须为Null;

5.复用性:

  5.1 功能复用:

    1. 有明确出口,入口的并且具有一定的功能性的可被重复使用的代码段,具备这些特征的代码都应该被提取封装成独立的可被重复使用的功能代码块;

  5.2 常量复用:

    1. 一般在系统模块中多次判断,赋值等操作的相关内容的数值和字符串,应该提取为可复用的常量,其中枚举就是典型代表;

6.注释规范:

  6.1 注释原则:

    1. 在重要,核心,难以理解的代码上需要添加注释,根据实际需要灵活掌控,通常每个对象每个方法都应该由注释;

  6.2 注释细则:

    1. 结构性注释:主要是工具自动生成的注释,包含对功能的描述,参数说明,返回值说明等;
    2. 普通代码注释:在特定的一些需要注意的代码行,在这行的上方新增一行进行注释,不要在代码后面进行注释,不便于发布清理注释,混淆加密代码功能的执行;
    3. 整体注释:在前后台文件编码开始处建议进行整体注释,包括,整体功能的描述,开发历史跟踪方便后续维护工作;

7.代码检测:

  7.1 检测内容:

    1. 通常VS已经帮我们检测和代码预编译的合理性,通常是提交的代码要保证VS的控制台不允许出现警告类型的消息;
    2. 随机抽取提交的代码编写,根据规范进行评比,这个一般和绩效挂钩;

  7.2 周期和范围:

    1. 这个根据不同企业来决定的,通常一周一次,随机抽取每个人新提交的代码;

此规范比较适用C#,是由我之前企业的技术老大编写,我这边巴拉过来存档使用,如果转载使用,请自行修改,添加自己的东西;

 

posted @ 2020-11-23 16:55  工具人Johnny  阅读(312)  评论(0)    收藏  举报