C# 编程指南

前不久在 Github 上看见了一位大牛创建一个仓库:CSharpCodingGuidelines,打开之后看了一下 readme.md 相关描述,感觉应该很不错,于是就 clone 到本地拜读一下,这里列一些自己的笔记,方便日后回顾。

基本原则

  • Astonishment 原则:你的代码应该尽量做到让每一个人都能理解。任何人都有写出让机器认识的代码,但是并不是每个人都能写出让人认识的代码;
  • Kiss 原则:类似 Python 之禅 里面说的那样,简单胜于复杂;
  • YAGNI 原则:代码尽量能做到可扩展,但请不要过度重构,因为你不能预知未来;
  • DRY 原则:不要重复造轮子,除非你有时间或者你造的轮子会比别人的优秀;
  • 面向对象编程原则:继承、封装、多态、抽象;

类设计指南

  • 一个类/接口应该只有一个用途,要符 合单一职责 原则;
  • 只创建返回有用对象的构造函数,当构造函数的参数超过 3 的话,你就应该考虑你的类设计是否过于臃肿;
  • 接口应该短小精悍,其定义要明确清晰地传达出其具有的行为;
  • 如果一种行为有多种实现,请考虑使用接口而不是基类;
  • 尽量使用接口将类进行彼此解耦;
  • 避免使用静态类;
  • 不要使用 new 关键字来禁止编译器显示相关警告;
public class Book
{
public virtual void Print()
{
Console.WriteLine("Printing Book");
}
} public class PocketBook : Book
{
public new void Print()
{
Console.WriteLine("Printing PocketBook");
}
} class Program
{
static void Main(string[] args)
{
PocketBook pocketBook = new PocketBook();
pocketBook.Print(); ((Book)pocketBook).Print(); Console.ReadKey();
}
}

在上述代码段中,我们创建一个基类 book,并定义了一个 Print() 方法,接着我们创建一个子类 PocketBook,并通过 new 关键字来重写基类方法。在项目复杂的情况下,使用这种方式将导致我们不能准确预测是子类调用还是父类调用,使代码复杂度提升。

  • 应该可以将派生类当作基类对象来处理;
  • 不要引用基类的派生类;
  • 避免暴露一个对象依赖的其它对象;
  • 避免双向依赖;
  • 类应该有状态和行为;
  • 类应该保护其内部状态的一致性;

属性成员设计指南

  • 允许按任意顺序设置属性;
  • 使用方法而不是属性;
  • 不要使用相互排斥的属性;
  • 属性、方法或者本地方法只应该做一件事情;
  • 不要通过静态成员公开有状态的对象;
  • 用 IEnumerable 或者 ICollection 来代替具体的集合对象作为返回值;
  • 如果属性、参数和返回值是字符串或者集合类型的话,则永远不应该为空;
  • 尽可能地定义具体的参数;
  • 考虑使用特定域的值类型而不是基元;

其他设计指南

  • 抛出异常而不是返回某种类型的状态值;
  • 提供完整而有意义的异常信息;
  • 抛出适当的最具体的异常;
  • 不要通过 try - catch 方式隐藏异常;
  • 正确处理异步代码中的异常;
  • 调用事件委托前先判断是否为空;
event EventHandler<string> Notify;
protected virtual void OnNotify(string args)
{
Notify?.Invoke(this, args);
}
  • 使用受保护的虚方法来触发每个事件;
  • 考虑添加属性变化事件;
  • 当触发事件时要确保 sender != nulll;
  • 如果合适的话,请考虑使用泛型约束;
class SomeClass
{
} /// <summary>
/// 不推荐
/// </summary>
class MyClass1
{
void SomeMethod<T>(T t)
{
object temp = t;
SomeClass obj = (SomeClass)temp;
}
} /// <summary>
/// 推荐
/// </summary>
class MyClass2
{
void SomeMethod<T>(T t) where T :SomeClass
{
SomeClass obj = t;
}
}
  • 在返回 LINQ 表达式之前计算它的结果;
  • 如果不是必须,不要使用 thisbase 关键字;

可维护性指南

  • 方法内部的代码段尽量不要超过 7 行;
  • 确保所有成员私有,类的类型默认为为 internal sealed
  • 避免双重条件;
  • 在其包含的命名空间内命名程序集;
  • 将源文件命名为它所包含的类型;
  • 将源文件的内容限制为一种类型;
  • 将不同的逻辑函数放到同一个部分类中;
  • 在使用一个类型时,使用 using 关键字导入需要的命名空间,而不是类型的完整空间标识;
  • 不要使用魔法数;
  • 只有当类型显而易见时才使用 var 关键字;
  • 定义变量时尽可能地初始化;
  • 在相互独立的代码段中定义临时变量;
  • 若对象有集合需要初始化的话在进行对象初始化的同时进行集合初始化;
  • 不要显式进行 bool 值的比较;
  • 避免嵌套循环;
  • 在使用 ifelsedowhileforforeachcase 的同时使用 {}
  • switch case 代码段中添加 default 逻辑;
  • 在所有的 ifelse if 后再添加 else;
  • 避免使用多个返回值;
  • 考虑使用简单的条件语句代替 if else
  • 封装属性、方法或局部函数中的复杂表达式;
  • 再合适的情况下尝试重载方法;
  • 使用可选参数来代替重载;
  • 避免使用命名参数;
  • 避免定义超过3个参数的签名;
  • 避免函数签名为布尔类型;
  • 不要将参数作为临时变量使用;
  • 将模式作为操作;
  • 不要注释代码;

命名指南

  • 不要在变量、参数和类型成员中包含数字;
  • 不要在字段添加前缀;
  • 不要使用缩写;
  • 成员、参数和变量定义要根据它们代表的意义;
  • 使用名词、名词短语或者形容词来定义类型;
  • 使用描述性名称命名泛型参数;
  • 在类成员中不要重复定义和类相同的名称;
  • 成员定义可参考 .Net Framework 的定义方式;
  • 避免使用可能被误解的段名称或字段;
  • 正确定义属性;
  • 在命名方法或局部函数时使用谓词或谓词对象;
  • 使用名称、层、谓词和功能申明命名空间;
  • 使用动词或动词前缀来定义事件;
  • 使用 ingend 后缀来表达事件预处理和发送事件;
  • 使用 on 前缀来定义事件处理程序;
  • 使用 Async 或者 TaskAsync 来标识异步方法;

性能指南

  • 使用 Any() 判断 IEnumerable 是否为空 ;
  • 仅对低密集型活动使用异步;
  • 对于 CPU密集型使用 Task.Run
  • 避免同时将 async/awaitTask.Wait 混合使用;
  • 避免 async/await 在单线程环境下出现死锁;

框架指南

  • 使用 C# 类型 别名而不是系量进行显式调用;
  • 不要硬编码;统命名空间中的类型;
  • 使用最高警告级别编译代码;
  • 对于简单的表达式避免使用 LINQ
  • 使用 lambda 表达式来代替匿名函数;
  • 只用在使用动态对象时才使用 dynamic 关键字;
  • 支持异步/等待任务延续;

文档指南

  • 使用美式英语来编写相关文档;
  • 文档中的代码部分要保证完整性;
  • 与其他开发人员一起编写 xml 文档;
  • 编写 MSDN 风格的技术文档;
  • 避免内联注释;
  • 注释值应该用来解释复杂的算法或讨论;
  • 不要使用注释来跟踪要在以后完成的工作;

布局指南

  • 使用常规布局;
  • 根据公式要求进行命名空间的约束;
  • 将成员置于定义良好的顺序中;
  • 谨慎使用 #region
  • 适当使用表现健全的成员;

相关链接

读 《CSharp Coding Guidelines》有感的更多相关文章

  1. 读javascript高级程序设计00-目录

    javascript高级编程读书笔记系列,也是本砖头书.感觉js是一种很好上手的语言,不过本书细细读来发现了很多之前不了解的细节,受益良多.<br/>本笔记是为了方便日后查阅,仅作学习交流 ...

  2. 读javascript高级程序设计-目录

    javascript高级编程读书笔记系列,也是本砖头书.感觉js是一种很好上手的语言,不过本书细细读来发现了很多之前不了解的细节,受益良多.<br/>本笔记是为了方便日后查阅,仅作学习交流 ...

  3. JavaScript: The Evil Parts - 1

    最近在看JavaScript框架设计,在讲解类型判定的时候提到了一些“匪夷所思的情况”,不过没有明说都是什么时候会出现这些情况.自己玩儿了一下,写写随笔吧.不过可能除了我找到的,还有会其他时候会出现这 ...

  4. 读 《JavaScript: The Good Parts》 有感

    提炼出一门语言或技术的 Good Parts, 使用该子集去构造健壮稳固的应用. 我们总是倾向于去学习和使用所有的语言特性,好像凡是新的,凡是提供了的, 就有必要去使用: 这本书告诉我们, 要有选择性 ...

  5. 读javascript高级程序设计17-在线检测,cookie,子cookie

    一.在线状态检测 开发离线应用时,往往在离线状态时把数据存在本地,而在联机状态时再把数据发送到服务器.html5提供了检测在线状态的方法:navigator.onLine和online/offline ...

  6. JavaScript: The Good Parts

    Chapter 1 Good Parts: JavaScript is an important language because it is the language of the web brow ...

  7. 读javascript高级程序设计01-基本概念、数据类型、函数

    一. javascript构成 1.javascript实现由三部分组成: ECMAScript:核心语言功能 DOM:文档对象模型,提供访问和操作网页内容的方法和接口 BOM:浏览器对象模型,提供与 ...

  8. 读javascript高级程序设计02-变量作用域

    一. 延长作用域链 有些语句可以在作用域前端临时增加一个变量对象,该变量对象在代码执行完成后会被移除. ①with语句延长作用域. function buildUrl(){ var qs=" ...

  9. 读javascript高级程序设计08-引用类型之Global、Math、String

    一.Global 所有在全局作用域定义的属性和方法,都属于Global对象. 1.URI编码: encodeURI():主要用于对整个URI编码.它不会对本身属于URI的特殊字符进行编码. encod ...

  10. 读javascript高级程序设计10-DOM

    一.节点关系 元素的childNodes属性来表示其所有子节点,它是一个NodeList对象,会随着DOM结构的变化动态变化. hasChildNodes():是否有子节点. var headline ...

随机推荐

  1. 端口转发工具lcx使用两类

    lcx是一款强大的内网端口转发工具,用于将内网主机开放的内部端口映射到外网主机(有公网IP)任意端口.它是一款命令行工具,当然也可以在有权限的webshell下执行,正因如此lcx常被认为是一款黑客入 ...

  2. R-CNN,SPP-NET, Fast-R-CNN,Faster-R-CNN, YOLO, SSD系列深度学习检测方法梳理

    1. R-CNN:Rich feature hierarchies for accurate object detection and semantic segmentation 技术路线:selec ...

  3. Mac OS X 恢复 VMware Fusion 虚拟机中的 vmdk 文件

    今天手贱把 VMware Fusion 虚拟机中的 Windows 10 搞挂了,原因是磁盘清理了下,然后重启就蓝屏了,Windows 10 自动修复.手动还原.手动重置系统,试过都不行,恢复系统是没 ...

  4. php使用curl模拟登录带验证码的网站[开发篇]

    需求是这样的,需要登录带验证码的网站,获取数据,但是不可能人为一直去记录数据,想通过自动采集的方式进行,如下是试验出来的结果代码!有需要的可以参考下! <?php namespace Home\ ...

  5. Docker 与 虚拟机比较

    1, 更高效的利用系统资源2,更快速的启动时间3,一致的运行环境4,持续交付(Continuous Integration)和部署(Continuous Delivery) 5, 更轻松的迁移 6,更 ...

  6. 谈谈 JavaScript 的正则表达式

    一.背景 最近在做 CMS 系统中不同身份登录用户的权限管理,涉及到对 api 路径的识别去判断是否放行.以前对正则表达式都是敬而远之,要用到的话都是直接复制粘贴现成网上的表达式,看也看不太懂,借这次 ...

  7. Linux链接脚本学习--lds

    一.概论 ld: GNU的链接器. 用来把一定量的目标文件跟档案文件链接在一起,并重新定位它们的数据,链接符号引用. 一般编译一个程序时,最后一步就是运行ld进行链接 每一个链接都被一个链接脚本所控制 ...

  8. Python语法基础——关于全局变量与局部变量

    1.函数内部的变量名如果第一次出现,且出现在=前面,即被视为定义一个局部变量,不管全局域中有没有用到该变量名,函数中使用的将是局部变量,例如: num = 100 def func(): num =  ...

  9. Spring 声明事务中transactionAttributes属性 + - Exception 实现逻辑

    下面是一段典型的Spring 声明事务的配置: <bean id=“baseTxProxy” lazy-init=“true”class=“org.springframework.transac ...

  10. RawConfigParser 与 ConfigParser ——Python的配件文件读取模块

    一般情况都是使用ConfigParser这个方法,但是当我们配置中有%(filename)s这种格式的配置的时候,可能会出现以下问题: configparser.InterpolationMissin ...