编程规范的目的
一个软件的生命周期中,80%的花费在于维护;
几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护;
编码规范可以改善软件的可读性,可以让程序员尽快而彻底的理解新代码;
为了执行规范,每个软件开发人员必须一致遵守编码规范;
使用统一编码规范的主要原因,是使应用程序的结构和编码风格标准化,以便于阅读和理解程序代码;
好的编码规范可使源代码严谨、可读性强且意义清楚,与其它语言约定相一致,并且尽可能的直观。
干程序,我们是专业的!
命名规范
通常来讲,名称是以意思相近的英文描述而命名的;例如:一个打开连接的方法 => open connection => OpenConnection();
到达 看其名,知其意 的效果;提高代码的可读性和理解性。
1. Pascal (大驼峰)命名方式
命名空间、类、接口、抽象类、结构体、枚举类、方法名、以及类中的属性,须要使用 Pascal 命名规范;名称中每一个单词的首字母都要大写;
例如:HttpClient、GetString() ;
在这里,本人还想分享一下我自己的编程习惯。
接口
官方文档中提到,接口的命名需要在其名称前加大写字母“I”,取自于 interface 关键字,例如:IDisposable、IDbConnection;
抽象类和枚举类
抽象类和枚举类是两种特殊的类,我们也可以在自定义的抽象类名称前加大写字母“A”,取自于 abstract 关键字,例如:ADataCollector 数据采集抽象类;
而对于枚举类,我们可以在自定义的枚举类名称前加大写字母“E”,取自于 enum 关键字,例如:ELogType 日志类型枚举类;
当然,这个只是我个人的小习惯,目的只有一个,更易于理解所写的代码;只要看到 A 开头的类名,就知道是自定义的抽象类,只要看到 E 开头的类名,就知道是自定义的枚举类。
(以上两点并不是必须的,根据个人意愿而为之)
实体类
实体类是非常常用的自定义类,类名最好用 “Entity” 结尾;例如:用户信息实体类 UserInfoEntity;好处也是易于理解,只要看到以 “Entity” 结尾的类名,就知道是一个实体类。
或者用 “Model” 结尾;例如:UserInfoModel 用户信息实体类。( 不推荐,因为 “Model” 释义为“模型”,模型与实体类还是有很大区别的 )
通用的工具类或帮助类
在实际开发中我们会自定义许多的通用类,以便提高开发效率,而这样的类,我们一般在其类名后面加上 “Tool”或“Utils”或“Helper” 结尾;例如:JsonTool、HttpUtils、SqlHelper 等。
2. Camel (小驼峰)命名方式
方法参数、局部变量、以及私有的成员变量,须要使用 Camel 命名规范;名称中第一个单词是小写的,从第二个单词起,后面每一个单词的首字母都要大写;
例如:
// 类中 私有的 成员变量
// 用来指示是否停止任务
private bool _isStopTask = true;
// 一个 sql 查询的方法
public DataTable QueryBySql(string sql, object paramList) // 方法参数
{
string tableName = "Test"; // 局部变量
DataTable data = new DataTable(); // 局部变量
// ... 其他代码
return data;
}
这里需要注意一点的是,对于私有的成员变量,须要在变量名前添加 “_” 下划线前缀,以便区分方法参数和局部变量。( C# 的源码里就是这么写的 )
3. bool 类型的命名
对于 bool 类型的方法、属性、参数、变量等,还是依据上面的命名规范,一般会在名称的前面添加 “is”或“Is”;( C# 的源码里就是这么写的 )
例如:isSucc 是否成功(参数或局部变量),IsFinish 是否完成(属性),IsChange() 是否改变(方法),_isStopTask 是否停止任务(私有的成员变量)等。
4. 控件命名
通常采用 控件名简写 + 英文描述,英文描述则使用 Pascal 命名方式;例如:登录按钮 btnLogin ,姓名输入框 txtName 等。
代码外观
1. 换行
当你的代码写在一行很长的时候,需要使用编辑器上的横向滚动条来拖动以便查阅时,这时候请务必考虑代码换行。
我们的目的只有一个 —— 不拖动滚动条就能看全代码。
如此一来,我们更方便的查阅代码,也更易于理解上下文的代码逻辑,不至于来回的拖动滚动条( 这样的操作真的很烦 )。
换行并不是随意的换行,我们是专业人士,需要注意一下两点:
在逗号后换行
示例:
// 此方式不可取
public static void WriteLog(string logFilePath, ELogType logType, string exeMethodName, string methodExeTime, string customMsg, string sysMsg = null, string addContent = null, string methodExeIdNum = null)
{
// ... 代码段
}
// 应采取这种方式
public static void WriteLog(string logFilePath,
ELogType logType,
string exeMethodName,
string methodExeTime,
string customMsg,
string sysMsg = null,
string addContent = null,
string methodExeIdNum = null)
{
// ... 代码段
}
在操作符前换行
示例:
// 此方式不可取
string url = $"http://pjcy.mof.gov.cn/billcheck/einvoice_page/queryEInvoice?billCode={entity.InvoiceCode}&billNumber={entity.InvoiceNumber}&randomNumber={entity.CheckNumber}&code={imgCode}&totalAmount={entity.InvoiceAmount}&date={entity.InvoiceDate}";
// 应采取这种方式
string url = $"http://pjcy.mof.gov.cn/billcheck/einvoice_page/queryEInvoice?"
+ $"billCode={entity.InvoiceCode}"
+ $"&billNumber={entity.InvoiceNumber}"
+ $"&randomNumber={entity.CheckNumber}"
+ $"&code={imgCode}"
+ $"&totalAmount={entity.InvoiceAmount}"
+ $"&date={entity.InvoiceDate}";
2. 空行
空行是为了将逻辑上相关联的代码分块,以便提高代码的可阅读性。
例如:
每一个方法之间至少有一行空行,如下图,
不同的逻辑块,加入空行,如下图,
3. 语句
每行最多包含一个语句,不要在同一行内放置一句以上的代码语句; 这会使得调试器的单步调试变得更为困难。
示例:
int a = 1; int b = a + 1; // 不可取
// 可取的
int a = 1;
int b = a + 1;
代码注解
代码注解就四种,//、///、/* */、#region #endregion;最基础的东西了,本人在这里就不再一一赘述其用法了;
在此我主要想说一下实际开发中的应用。
1. 注解一定要保持最新,一旦代码变更,相关的注解也要跟着变更释义,时刻保证自己或他人能够看懂理解。
2. 注解一定要写在相关代码的前一行,或代码本行的末尾处;切记,不可把注解写在相关代码的后面一行( 下面一行 )。
3. 避免多余的或不适当的注解,移除所有无关的注解。
4. 对于类、接口、成员的注解,强烈推荐使用 /// 注解,这样在对其调用和使用时,可以直接看到注解信息,如下图,
5. 善用 #region #endregion 预处理指令;#region 是一个分块预处理指令,它主要用于编辑代码的分段,在编译时会被自动删除;
在这里我不得不说一个现象,总是有一些小伙伴喜欢每一个方法外面都套一组 #region #endregion ,这并不是一个好习惯。
通常我们使用 #region 来给相关联的一片长代码分段,而不是滥用这个指令。例如:一组( 多个 )相关联的方法或一段长逻辑的代码 等,如下图,
文件定义
1. 通常情况下,一个 cs 文件只定义一个 类、接口、枚举、结构体;只有特殊情况可将多个类定义在同一个 cs 文件中,而这 必须是紧密关联的多个类。
2. 类名应该与 cs 文件名保持一致,以便于通过文件名查找到类;例如 UserInfo 类 应该在 UserInfo.cs 文件里。
需要注意的常规性编程问题
1. try { } catch { throw } 异常处理
不要出现如下所示的无意义的 try - catch { throw } 代码块;
// 1.
try
{
// ... 可能会抛异常的代码段
}
catch (Exception ex)
{
throw ex;
}
// 2.
try
{
// ... 可能会抛异常的代码段
}
catch (Exception)
{
throw;
}
如果你的代码里有像上面一样的 try - catch { throw } 写法,在此强烈建议你移除像这样的 try - catch { throw } 写法。( 你可以去查阅官方文档,以理解 try - catch { throw } 几种不同写法的区别 )
推荐使用下面的写法:
try
{
// ... 可能会抛异常的代码段
}
catch (Exception ex)
{
throw new Exception("自定义的异常消息", ex);
}
2. 字符串拼接
当遇到长字符串的拼接时,强烈建议你使用 StringBuilder 类型来拼接或处理字符串。( 这种情况下不要使用 string 类型 )
例如:较长的 SQL 语句拼接,如下图
3. 自定义枚举类
第一,枚举类不要去继承 int 类型,或是其他的整数型类型。若你要使用枚举类中枚举项的实际数值,请使用强类型转换。
第二,枚举类中的枚举项,一定要赋值于一个固定的数字( 以免在后面扩展枚举项时混淆枚举项的实际值 )。如下图:
Visual Studio IDE 的巧用
1. 每次在写完代码保存之前,按一次 Ctrl + E + D 快捷键( C#开发环境,如果不是请自行设定 IDE 的开发环境 ),编辑器会自动格式化代码,一是代码美观,二是易于阅读代码。
2. 当一个 cs 源代码文件完成后,请回到顶部,移除多余的 using 引用( 快捷键 Ctrl + R + G );如下图:
3. 解决并消除有警告的代码,如下图:
通过 IDE 点进去查看有警告的问题代码,解决并消除它们,以确保你的项目中没有问题代码。