dotNET Core:编码规范
在项目开发过程中,由于时间紧、任务重,很容易导致面向功能编程。实现相同的功能,代码可以写的很优雅,也可以写的很晦涩和复杂。现在的工作,都需要进行团队协作,代码就需要有一定的规范进行指引,因为我们需要写出让人可以轻易读懂的代码,而不仅仅是机器。
规范没有绝对的标准,遵循大部分人都认可的一种方式就可以了,保持统一。比如在 dotNET Core 中,我们可以参考下 dotNET Core 的源码,最终制定一个适合团队的规范即可。
下面是我理解的正确的一些规范:
基本准则
1、命名的规范分为两种:Pascal(大驼峰)和驼峰(小驼峰),示例如下:
• Pascal:UserName
• 驼峰:userName
2、命名要有意义,需要看到名称知其含义。少用拼音和匈牙利命名法。
示例 | |
---|---|
Int price=20; | √ |
UserInfo userInfo=GetUserInfo(userId); | √ |
Int p=20; | × |
Int intPrice=20; | × |
3、对于类的成员变量,用this关键字,增强代码可读性。
4、对于基类的成员变量,用base关键字,增强代码可读性。
名称规范
好的名称可以让我们减少很多不必要的注释,可以让代码阅读者很容易就理解代码的意思。但命名不是一件容易的事情,在命名的时候,通常伴随着我们对代码逻辑的思考。比如:如果你不能给一个函数很准确地命名,那可能这个函数的职责不单一,做的事情太多,才导致一个名称很难概括,意味着代码可能需要重构。好的命名是我们写好代码的基础。
命名空间
命名空间采用Pascal命名法:
namespace Fw.Application{}
namespace Fw.SmartFlow.Acitivity{}
实际工作中,我们会将很多逻辑上属于同一类的文件,在物理上分成不同的目录,这时建议修改命名空间为相同的命名空间。
类
类采用Pascal命名法:
public class UserService{}
类是对属性和方法的封装,类有很多的种类:
跟数据库表对应的实体类
处理业务逻辑的业务类
提供扩展方法的扩展类
接口层的数据传输类
不同的种类可以约定俗成地进行一些名称的约束,比如扩展类用 Extension 结尾、接口层的使用 Request、Response 结尾,等等,这样在阅读代码时就知道什么类的职责是什么。
接口
接口采用大写I+Pascal命名法:
public interface IUserService{}
方法
方法采用Passcal命名法:
public string GetUserName(){}
方法的命名需要比较具体,越抽象的名称越难以理解。例如,InitData() 就是一个不太好的名称,改成 InitConfiginfo() 会更好些。另外,方法的命名在同一类型的语义下要保持一致,在一些项目中看到查找类的方法,有 GetXXX、QueryXXX、FindXXX 等等。五花八门的方式会提升阅读的成本。
变量
变量分为:类变量、静态类变量、只读变量、静态只读变量、方法变量。
类变量:
private string _userName;
类变量只能使用 private 修饰符,如果需要暴漏出去,或是给子类使用,使用属性来进行封装。
静态类变量、只读变量、静态只读变量:
private static readonly ResourceManager _resourceManager;
public static readonly IRouter Instance = new MockRouter();
• 修饰符为 private: _ + 驼峰命名法;
• 修饰符为 public: Pascal 命名法;
• 修饰符为 protected:Pascal 命名法;
方法变量:
bool isCheck;
常量:
常量采用Pascal命名法:
public const string AuthorizationFilter = "Authorization Filter";
属性:
属性采用 Pascal 命名法:
public BasicApiContext DbContext { get; }
参数
参数采用驼峰命名法:
public List<BizApp> GetBizAppList(string userId,DeviceType deviceType)
注释规范
注释是一把双刃剑,当代码中存在大量的注释的时候,我们第一反应会先看注释,并会默认注释中写的内容是对的,真实情况是注释往往会给我们错误的指导。有两个原因:
当代码逻辑发生变化时,只修改了代码,注释没有调整;
不同的人员都对注释进行编辑,慢慢注释会变得和代码不匹配。
Martin Fowler 在他的经典书籍 《重构》 中也提到过多的注释是一种坏味道的体现,他认为,当你觉得需要写注释的时候,应该先想想是不是可以进行重构。那是不是程序中就不应该出现注释呢?当然不是,我认为下几种情况是需要写注释的:
时间紧急,临时写的一些 ”烂代码“,需要写注释,说明原因,一般需要加上 TODO ;
复杂算法类的方法,可以写注释说明逻辑;
写的是偏底层的类库,对外暴露的方法需要写注释,调用方能方便在智能提示中显示;
如果你的能力写不好代码,那还是先把注释写上吧。
异常规范
异常的目的是用来报告错误,这也是他的唯一目的,所以避免在返回值中来返回错误信息,所有的地方都应该使用抛异常的方式来报告错误;
使用抛异常的方式可以防止错误的操作继续执行;
要能够预估到会出现什么异常,知道是什么类型的异常,才 Try 住做相关的处理;
最终用户友好和对开发者友好;
暴漏问题比隐藏问题要好,隐藏问题只会导致更严重的问题。
详细的异常处理可以参考之前的文章:
dotNET:怎样处理程序中的异常(理论篇)?
dotNET:怎样处理程序中的异常(实战篇)?
空行规范
空行规范是一个很简单的规范,就是在每个方法中,代码应该按照不同逻辑的逻辑块进行分割显示,虽然简单,但如果不注意,还是会对代码的阅读带来很大的障碍。下面看看 dotNET Core 的源码 CreateDefaultBuilder 方法:
public static IHostBuilder CreateDefaultBuilder(string[] args)
{var builder = new HostBuilder();builder.UseContentRoot(Directory.GetCurrentDirectory());builder.ConfigureHostConfiguration(config =>{config.AddEnvironmentVariables(prefix: "DOTNET_");if (args != null){config.AddCommandLine(args);}});builder.ConfigureAppConfiguration((hostingContext, config) =>{var env = hostingContext.HostingEnvironment;config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName)){var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));if (appAssembly != null){config.AddUserSecrets(appAssembly, optional: true);}}config.AddEnvironmentVariables();if (args != null){config.AddCommandLine(args);}}).UseDefaultServiceProvider((context, options) =>{var isDevelopment = context.HostingEnvironment.IsDevelopment();options.ValidateScopes = isDevelopment;options.ValidateOnBuild = isDevelopment;});return builder;
}
想想看,上面代码中如果去掉空行会读起来是什么样的感受?
日志规范
在一个完整的系统中,日志非常的重要。在 dotNET Core 中自带了日志功能,当然我们也可以使用第三方的 NLog、Serillog 等。
这些日志框架都提供日志级别功能,比如:INFO、DEBUG、WARN 和 ERROR 等,这些级别对程序出错时的排查非常有用,所以在记录日志时一定不要都使用 INFO 或者都使用 ERROR 了。
除了级别,日志的类型有这么几类:
操作日志
业务日志
错误日志
操作日志
系统中所有的操作的都记录下来,包括登录、数据的增删改等,主要用来做审计,数据异常操作时的追责等。
随着时间的推移,日志的数据量会越来越大,所以需要考虑存储的方式,比如阶段性地将历史日志进行存档。
业务日志
用户在界面中输入数据,点击一个按钮,程序中会进行一系列的处理最终返回结果给用户,在这个过程中对一些关键的业务信息进行记录,可以在系统出现问题时方便排查和追踪。
错误日志
错误日志的主要目的就是排错,所以记录的信息一定要是对排错有帮助的信息,尽可能地记录详细,比如整个堆栈信息、调用链等。比如,你去进行错误排查时,发现记录的信息是”未将对象引用到对象的实例“,你依然不知道错误的原因是什么。
总结
谈及代码的时候,都会去聊架构、模式,这些固然重要,但编码习惯和规范也不可小视。一份产品的代码怎样才能变得越来越好,这需要团队每个人成员共同的努力,一个人掉链子,很容易就形成破窗效应,导致坏味道越来越多。
写好的代码,是每个有追求的技术人的使命和职责。
希望本文对您有所帮助。
dotNET Core:编码规范相关推荐
- .Net基础——程序集与CIL HttpClient封装方法 .Net Core 编码规范 C#中invoke和beginInvoke的使用 WebServeice 动态代理类...
.Net基础--程序集与CIL 1. 程序集和CIL: 程序集是由.NET语言的编译器接受源代码文件产生的输出文件,通常分为 exe和dll两类,其中exe包含Main入口方法可以双击执行,dll则需 ...
- .Net Core 编码规范
.Net Core 编码规范 标签: 未分类 概述 规范制定原则 方便代码的交流和维护. 不影响编码的效率,不与大众习惯冲突. 使代码更美观.阅读更方便. 使代码的逻辑更清晰.更易于理解. 术语定义 ...
- SonarQube系列二、分析dotnet core/C#代码
来源:https://www.cnblogs.com/7tiny/p/11342902.html [前言] 本系列主要讲述sonarqube的安装部署以及如何集成jenkins自动化分析.netcor ...
- 前端编码规范,个人感觉bootstrap总结的不错,拿出来给大家分享
前端编码规范,个人感觉bootstrap总结的不错,拿出来给大家分享 http://codeguide.bootcss.com/#html-doctype HTML 语法 HTML5 doctype ...
- dotNET Core WebAPI 统一处理(返回值、参数验证、异常)
现在 Web 开发比较流行前后端分离 现在 Web 开发比较流行前后端分离,我们的产品也是一样,前端使用Vue,后端使用 dotNet Core WebAPI ,在写 API 的过程中有很多地方需要统 ...
- 通过Swashbukle给DotNet Core Web API 增加自动文档功能
DotNet Core Web API给开发者提供了一个很好的框架来开发Restful的API.那么这些API接口该如何管理起来呢?Swagger是一个很好的选择,Swagger不需要开发者额外去维护 ...
- [SSCore] 开源dotnet core 版本 SuperSocket
前言碎语 最近一直在做旧版本dotnet 程序迁移至dotnet core的工作, 非常欣慰dotnet社区的蓬勃发展, 目前大部分的第三方类库或开源代码都有了dotnet core版本 或者可以方便 ...
- Unreal Engine 4 编码规范
On this page: 简介 类的组织结构 版权声明 命名规范 示例 基本C++数据类型的可移植别名 注释 指南 示例格式 C++ 11和现代语法 原有宏的新关键字 'auto'关键字 Range ...
- PHP - Yii2编码规范/风格[PSR-1/PSR-2]
编码规范还是要了解的,但是有时候太多记不住/记不全,所以更好的解决方案是通过插件/脚本 1. 自动化工具 StyleCI // https://styleci.io/ 如果你的代码格式不是很完美,不必 ...
最新文章
- 借助Glances Monitor,密切关注你的系统
- 如何用#define宏定义多行函数
- bzoj5183 [Baltic2016]Park
- windows kernel 可以直接读写文件系统资料吗_嵌入式杂谈之文件系统
- 不借助Maven,使用Eclipse创建Hello World级别的Spring项目
- 【Transformer】HRFormer:High-Resolution Transformer for Dense Prediction
- HDU 1757 A Simple Math Problem (矩阵快速幂)
- 开源开放 | 多模态实体链接数据集MELBench(CCKS2021)
- 关于python2到python3更新的一些书写规则的更改
- dict keys 取最后一个_一步一步学Python3(小学生也适用) 第十三篇: 字典Dict类型
- oracle insert into as select,比较create table as select * 与 insert into table select *
- 移动端安全测试主要涉及_Android APP安全测试基础
- OpenCV+MFC显示图像
- noip模拟赛 寻宝之后
- CMU 15-213 Introduction to Computer Systems学习笔记(3) Floating Point
- 以VS2017+OpenCV3.4.7+opencv_contrib3.4.7 为例,用cmake编译,实现所有版本轻松编译,其他版本组合都可借鉴
- C#上位机工作感想1(2020.7.1-2021.4.4)
- 量子化学计算机理,量子化学计算在反应机理确证中的应用
- HTML5篮球弹跳运动规律,篮球体能训练的七大原则
- symbian与uiq开发教程[完整版]
热门文章
- #UnityTips# 2017.11.14
- 【Linux】【Services】【nfs】nfs安装与配置
- 看出每个应用程序最高可用内存是多少
- 转载:Pixhawk源码笔记一:APM代码基本结构
- 第2天:汇编语言与Makefile
- oracle服务器不识别tc服务,记一次ORACLE无法启动登陆事故
- 自定义异常最佳实践_播放,自定义和组织媒体的最佳文章
- linux 桌面显示视频播放器,Ubuntu 13.10开启媒体播放器VLC桌面通知的步骤
- vue-typescript
- OC之非ARC环境下循环retain问题