THE ELEMENTS OF C# STYLE

|前言

程序员其实艺术家,灵动的双手如行云流水般在键盘上创造着生命的奇迹,我认为代码是有灵魂的。同一个模块,在每个程序员手中所缔造出来的是不相同的。

最终,这个模块或者实现了最初的业务,但是回过头看看你的作品,你会认为她是你的艺术品,还是她就是一坨Code?

好吧,为了普及C#是最美的编程语言这种思想,我决定写这篇【THE ELEMENTS OF C# STYLE】,欢迎吐槽!

|一般原则

1. 坚持最小惊奇原则
   简单性(Simplicity)
   用简单的类和简单的方法满足用户期望
   清晰性(Clarity)
   确保每个类、接口、方法、变量和对象都有清晰的目的,并阐明何时、何处、如何使用它们
   完整性(Completeness)
   提供任一可能的用户期望找到和使用的最小功能,创建完整的文档,描述所有特性和功能
   一致性(Consistency)
   相似实体的外观和行为应该相同,不同实体的外观和行为应该不同,应该尽可能制定和遵守相关标准
   健壮性(Robustness)
   对软件中可能出现的错误和异常做出预测,并将解决方法记入文档,不要隐藏错误,也不要等着用户去发现错误
2. 第一次就做对
3. 记录所有规范的行为

|格式

1. 第一次就做对

1.1. 使用快捷键 Ctrl + K + D 来格式化 .CS 代码
1.2. 在流程控制语句中使用语句块花括号
但若控制体中为以下单句语句,可以不使用花括号
return, break, continue, throw, yield return, goto

      if(a<2) return;

2. 类的组织

2.1.使用 .CS 文件右键菜单中顶部的Organize Usings-> Remove and Sort 来整理 using 指令
2.2.使用 #region 将源代码组织到不同区域中

推荐使用ReSharper的 File Structure 窗口方便的管理代码结构(快捷键Ctrl + Alt + F)

一般可以考虑按以下类型和访问级别组织类成员:
      #region [Fields]
      #region [Embedded Types]
          … 这里放public 成员
      #region [Protected]
      #region [Private Methods]
    区域尽量不要嵌套多层
2.3.单独声明每个变量和特性(每行只放一个)
不建议的书写方式:

      int a;int b;int c;

|命名

1. 一般原则

1.1. 使用有意义的名称
      应该使用对读代码的人来说有意义的名称,避免使用单个字符或太一般性的名称(特别是在方法内部实现中)
1.2. 根据含意而非类型来命名
      类型信息一般可从其用法和智能感知中看出来,如:使用Customer 而不是CustomerClass对于UI控件的命名可以加上控件的类型,如:CustomerNameLabel、 FeedBackButton
1.3. 使用熟悉的名称(目标领域通用的术语)
1.4. 不要用大小写来区分名称
      虽然编译器区分大小写,但这样会影响代码可读性,如:XMLStream和XmlStream
1.5. 避免使用过长的名称
      对象的名称应当足以描述其目的,如果名称过长,可能说明该实体企图实现的功能太多,此时应当考虑是否需要重构
1.6. 加上元音 – 使用完整的单词
      不要通过去除元音来缩短名称,这样会降低代码可读性,有时还可能产生歧义
      如:不要使用 public Msg AppendSig(),而应该使用 public Message AppendSignature()
1.7. 不要出现拼写错误,第一次就拼对!

2.缩略形式

2.1、除非全称太长,否则不建议使用缩略形式
     不要使用不必要的缩略词,这样会影响可读性,如:使用Attachment 而不是Atta
     如果必须使用缩略词,请使用广为使用和接受的缩略词,如:Api、App、Zip
2.2. 像普通词一样书写缩略词
     不要全都大写,如:XmlString 而不是 XMLString

3.类型和常量

3.1. 建议使用Pascal写法给命名空间、类、结构、属性、枚举、成员常量及方法命名
     每个单词首字母都大写,如:DataManipulator
3.2. 建议使用名词命名类、结构和属性
     如: NetworkManager、 public string NetworkType { set; get; }
3.3. 建议用复数形式书写集合名称
     集合对象的名称应该有能反映集合中对象类型的复数形式,
     差:List<Shape> shapeList = new …
     好:List<Shape> shapes = new …
3.4. 建议给抽象基类加上Base 后缀
     如:public abstract class AccountBase
     public class PersonalAccount: AccountBase
3.5、使用单个大写字母命名泛型参数
    单个泛型参数使用<T>,多个泛型参数将T作为前缀,如:<TKey, TValue>
3.6、给实现了一种设计模式的类添加模式名称
    如:public class MessageFactory

4.枚举

4.1. 用单数形式为(一般)枚举命名
    如:public enum EnhancementMode
4.2. 用复数形式为位域枚举命名
    如,定义时:

       public enum Languages
      {
         English = 1,
         ChineseSimplify = 1 << 1,
         ChineseTraditional = 1 << 2,
         …
      }

使用时(通常与位或操作符一起使用):

    var languages = Languages.English | Languages.ChineseSimplified | Languages.ChineseTraditional

5.接口

5.1. 用大写字母 I 作为接口名称的前缀(IInterface)名
5.2. 使用名词或形容词给接口命名
       若接口声明了对象提供的服务,可用名词命名,如:public interface IMessageListener
       若接口描述了对象的能力,可使用带-able或-ible后缀的形容词命名
       如:public interface IReversible

6.属性

6.1. 根据Getter和Setter的值来为属性命名
      如对于一个取得过期日期的属性,将其命名为ExpirationDate
6.2. 避免冗长的属性名称
      如:使用Icollection Customers,而不用Icollection CustomerCollection
6.3.用能体现布尔值特性的名称给bool类型的属性命名
      视含意添加Is、Has等前缀,如:bool IsOpen, bool HasCompleted

7.方法

7.1. 使用Pascal写法为方法命名
    每个单词首字母都大写,如:ParseSecondsFrom1970
7.2. 避免冗长的方法名
    操作类名对象的类的成员方法名中不需要再带有该类对象名
    如:在Book 类中,使用方法Open(),而不是OpenBook()

8.变量和参数

8.1. 使用Camel写法为变量和参数命名
    第一个单词的首字母小写,后面每个单词的首字母大写,如:lastName
8.2. 用名词命名变量和参数
8.3. 给字段(Fields)名称加上下划线前缀_,使之与其他变量区分开来
    如:_lastName
8.4. 用一系列标准名称为“一次性”变量和参数命名
   •循环变量int i, j, k
   •object o, obj
   •string s, str
   •Exception e, ex
   •EventArgs args

9.特性

9.1. 给自定义特性加上Attribute后缀
    定义时:
    public class MyCustomAttribute: Attribute { … }
    使用时:
    [MyCustom]
    public class CertainClass{ … }

10.事件、异常

10.1. 事件的名称应当包括对象及动作的描述
     如:public event EventHandler<MessageReceivedEventArgs> MessageReceived
10.2. 事件对应的参数类型应当添加EventArgs后缀,并继承自EventArgs类
     public class MessageReceivedEventArgs: EventArgs
    {
       //…
     }
10.3. 事件所在的类中应当有一个名为OnEventName()的方法用于触发事件
10.4. 给自定义异常类型添加Exception 后缀
     public MyCustomException: Exception
    {
      //…
    }

|文档

1.一般原则

1.1. 为使用接口的人编写软件接口文档
    编写代码中公共接口的文档,可以让别人正确、高效地理解和使用接口
    编写文档注释的首要目的是在服务的提供者(supplier)和客户(client)之间定义一种编程契约(programming contract)
    与方法相关的文档应该描述与该方法的调用者有依赖的行为的诸多方面,而不应试图描述其实现细节
1.2.为维护者编写代码实现文档
    总是假定会有完全不熟悉你的代码的人要阅读和理解你的代码
1.3.保持注释和代码同步
    修改代码时,也要确保更新相关注释
    代码和文档一起构成软件产品,应对其同等重视
   “When the code and the comments disagree, both are probably wrong.”–Norm Schryer, Bell Labs
1.4.尽早编写软件元素的文档
在实现之前或实现过程中编写软件元素的文档,勿拖延至软件将近完成才编写,因为对代码太过熟悉或太过厌烦,在项目结尾做的文档往往缺少细节
如果在实现之前编写软件参考文档,则可以使用该文档为受托实现软件的开发人员定义需求
1.5.考虑全世界的读者

2.API

1.尽量使用C#内建的文档机制
   使用<summary>等标签编写文档,之后VS可自动生成API文档
   使用NDoc等工具可自动生成可满足各种需求各种格式的文档
   常用标签:

Ctrl + Shift + F1

  

3.内部代码

3.1. 只在需要帮助别人理解代码的时候才添加内部注释
3.2. 解释代码为什么要这样做
3.3. 避免使用C风格的注释块 /* … */
3.4. 使用单行注释 // 描述实现细节
      特定变量或表达式的目的
      实现层面的设计决定
      复杂算法的来源资料
      缺陷的修正或变通方法
      以后可能做优化或加工的代码
     任何所知的问题、局限或缺陷
3.6. 使用关键词标出待完成工作、未解决问题、错误和缺陷修正

 

|编程

1.类型

1.1.使用内建的C#类型别名
    别名更加简洁易读,而且具有关键字语法着色
    例如:使用int,而不是System.Int32;string,而不是String;object,而不是Object
1.2. 避免使用内联字面值
   不要:if (size > 45) 
   而是:const int limit = 45; if (size > limit) 
   这样不但改善了可读性,而且便于在一个位置修改
1.3.避免不必要的值类型装箱拆箱

1.4. 使用标准形式书写浮点字面值
   差:const double foo = 0.000042;
   好:const double foo = 4.2e-5;
1.5. 将“值”语义定义为struct(而不是class)
   选用struct表示其实例在堆栈上创建
   注意struct不能继承和派生(是密封的),而且没有默认的构造器
1.6. 避免使用代价较高的隐藏式字符串分配
   代码if (str1.ToUpperCase() == str2.ToUpperCase()) 将产生2次字符串分配
   可以优化为if (string.Compare(str1, str2, true))
1.7. 采用更高效的空字符串检测方法
   差:if (str == “”)
   好:string.IsNullOrEmpty(str) / string.IsNullOrWhiteSpace(str)
1.8. 只在必要时使用可空值类型
   因为需要装箱拆箱,所以请确认只在有必要的情况下使用可空值类型

2.语句和表达式

2.1. 在复杂表达式中使用括号,而不要依赖操作符优先级
   差:varj = 10 * 2 << 1 + 20;
   好:varj = (10 * (2 << 1)) + 20;
2.2. 不要将布尔值与true 或false 进行相等比较
   if (popup.IsOpen == true) 这没有必要!应当总是直接判断布尔值if (popup.IsOpen)
2.3. 使用静态方法object.Equals() 测试引用类型等同
   因为某个类型的实例方法Equals() 和操作符 == 可能已被重写
   if (object.Equals(str1, str2))

3.类

3.1. 定义小类和小方法
   较小的类和方法易于设计、编码、测试、编写文档、阅读、理解和使用,较小的类通常拥有更少的方法,能表达更简单的概念
   尽量将每个类的接口(指对外暴露的功能)限制在提供必要功能所需的最少法之内
   尽量将较大的方法拆分出一些较小的私有方法,即使这些小方法只被调用一次,因为切割开的代码更容易阅读和重用
   另外,CLR可以对小方法进行更好的代码优化
3.2. 声明所有成员的访问级别
   不要假设别人会记得默认的访问级别,应当全部写出,并按原则上public, protected, private 的顺序排列
3.3. 合理避免使用internal 声明
   internal成员通常标志着不好的设计,因为它绕过了访问限制,而且隐藏了类和成员之间的关系
   你能说出protected internal 的访问级别吗?
   仅在以下情况下考虑使用internal:
   •某工具类仅提供给同程序集中的其他类使用,不需要暴露给程序集的使用者
   •需要防止派生类获得特定父类方法,但又同时允许特定辅助类等访问这些方法

4.字段、属性、方法

4.1. 声明所有字段为private,使用属性提供访问
将实现细节看作私有信息,降低在实现改动时对依赖类的影响,并且让数据持续有效
4.2. 只为简单、低成本、顺序无关的访问使用属性
即不应有副作用、开销大、与访问顺序有关
4.3. 方法中避免传递过多参数
如果某个方法需要大量参数,就应该考虑是否要重新设计了,参数太多标志着方法做了太多的事,或者数个相关参数可以被抽象到另一个类里

5.异常

5.1. 使用返回码(return code)报告预期的状态改变
5.2. 使用异常强迫获得编程契约
    •前置条件异常(pre-conditional exception):参数无效或调用方法时相关对象处于无效状态
    •后置条件异常(post-conditional exception):方法产出结果无效或在返回前相关对象处于无效状态
    与方法调用者有关时才抛出异常,如果是内部逻辑错误,则应使用断言(Debug.Assert)
5.3. 不要静默地接受或忽略非预期的运行时错误
    不要使用空的catch 块消除异常
5.4. 只捕获能处理的异常
    合理避免使用通用的catch (Exception ex) { … }
5.5.使用try…finally… 代码块或using 语句管理资源
5.6.尽可能抛出最具体的异常
    NullReferenceException, ArgumentOutOfRangeException, FileNotFoundException
5.7.按照异常类型的特殊性级别排列catch 块
    先捕获更特殊的异常
5.8.不要在finally 块中抛出异常
    在finally 块中抛出异常会导致同时激活多个异常,很难处理

6.效率

6.1.使用懒惰求值和懒惰初始化(lazy evaluation & lazy initialization)
   原则:
   在需要结果之前,不要进行复杂的计算
   总是在最靠近嵌套边缘的地方执行计算
   如果可能,缓存结果
   在需要对象之前,不构造对象(可能需要加锁来防止并发初始化)
6.2.重用对象以避免再次分配
   缓存并重用频繁创建且生命周期有限的对象
   使用访问器而不是构造器来重新初始化对象
   使用工厂模式来封装缓存和重用对象机制
6.3.避免创建不必要的对象
   特别是新对象生命周期较短,或者构造后从来不引用时,尤其需要注意
   在知道自己需要什么之前,避免创建对象

 

6.4.让CRL处理垃圾回收
   一般而言,避免调用GC.Collect() 方法,让垃圾回收器自行动作
   在多数情况下,垃圾回收器的优化引擎比你更善于判断执行回收的最佳时机
6.5.到最后再进行优化
   优化的第一原则:
   不要优化
   优化的第二原则(只针对专家):
   还是不要优化
   在确认需要优化之前,不要花时间做优化
   确实要做优化时,应采用80-20原则:平均而言,系统中20%的代码使用80%的资源,确保从这20%的代码开始优化

|推荐

神器Resharper非常好用,推荐安装,让你爱上Coding!

THE ELEMENTS OF C# STYLE

时间: 2024-10-10 19:52:30

THE ELEMENTS OF C# STYLE的相关文章

《世界是数字的》阅读笔记

<世界是数字的>是由世界顶尖计算机科学家Brian W.Kernighan写的,Brian W.Kernighan曾为贝尔实验室计算机科学研究中心高级研究人员,现为普林斯顿大学教授.他是AWK语言和AMPL语言的发明人,还参与过UNIX和许多其他系统的开发,同时出版了The C Programming Language.The Practice of Programming.The Elements of Programming Style等在计算机领域影响深远的著作. Kernighan主张

小小鸟 读后感

我是IT小小鸟 读后有感 阅读此书后的感觉和心得体会如下. 对于专业兴趣是第一原则 要尝试发现你的兴趣所在.特长所在,然后围绕这些来确定发展方向,不盲目从众和跟风. . 他山之石,可以攻玉,但不可照搬(借用书中). 因为环境不同,时代不同.更重要的是每个人都是独一无二的. 其他书中的作者大多出身"名门",有北大.清华.南大.华工等国内知名院校 而我的本科却是在一所普通大学,这是有差异的,想要不输于他人唯有默默积聚实力,最终突破环境的限制,登上一个新台阶 但是基础薄弱却又被外界所影响 颓

面板Panel

Basic Panel The panel is a container for other components or elements. Open Close Basic Panel jQuery EasyUI framework helps you build your web pages easily. easyui is a collection of user-interface plugin based on jQuery. easyui provides essential fu

高级Java程序员值得拥有的10本书

Java是时下最流行的编程语言之一.市面上也出现了适合初学者的大量书籍.但是对于那些在Java编程上淫浸多时的开发人员而言,这些书的内 容未免显得过于简单和冗余了.那些适合初学者的书籍看着真想打瞌睡,有木有.想找高级点的Java书籍吧,又不知道哪些适合自己. 别急,雪中送炭的来了:下面我将分享的书单绝对值得拥有.ps,我也尽力避免列出为特定软件或框架或认证的Java书,因为我觉得那不是纯Java书. 1.<Java in a Nutshell>(Java技术手册) 与其说是必读书籍,还不说是参

web项目开发 之 前端规范 --- JavaScript编码规范

JavaScript编码规范 此文严格按照W3C规范和部分实际项目可读性,浏览器加载,性能等众多属性权衡,做出平时前端编码规范文档.供广大web工作者参考并实施,对维护和项目扩展升级都能省时省力. 场景:web前端开发中 一些Javascript的注意事项 和 规格建议: [参考百度资料 和个人一些总结] 1 前言 JavaScript 在百度一直有着广泛的应用,特别是在浏览器端的行为管理.本文档的目标是使 JavaScript 代码风格保持一致,容易被理解和被维护. 虽然本文档是针对 Java

闲的时候看看(怎么可能有闲的时候)

<程序猿幼崽上路指南> UNIX编程艺术UNIX网络编程代码大全// apache的源码<Pragmatic Programmer>.<The Art of UNIX Programming>.<Elements of Programming Style>和<The Productive Programmer>Large-Scale C++ Software Design 分析与设计://c++的对象机制,设计模式,大规模设计Object-Ori

Phalcon之教程 2:INVO 项目讲解(Tutorial 2: Explaining INVO)

教程 2:INVO 项目讲解(Tutorial 2: Explaining INVO) In this second tutorial, we'll explain a more complete application in order to deepen the development with Phalcon. INVO is one of the applications we have created as samples. INVO is a small website that a

用CKEDITOR 做自助上传的解决方案2

1,在plugins下新建文件夹 multiimg 2,创建文件plugin.js (function() { CKEDITOR.plugins.add("multiimg", { requires: ["dialog"], init: function(a) { a.addCommand("multiimg", new CKEDITOR.dialogCommand("multiimg")); a.ui.addButton(&

CSS中强大的EM

使用CSS也好久了,但一直都是在使用"px"来设置Web元素的相关属性,未敢使用"em".主要原因是,对其并不什么了解,只知道一点概念性的东西,前段时间在项目中要求使用"em"作为单位设置元素,所以从头对"em"学习了一回.稍为有一点理解,今天特意整理了一份博文与大家一起分享,希望对童子们有些许的帮助. 这篇教程将引导大家如何使用"em"来创建一个基本的弹性布局,从而学习其如何计算?又是如何使用"