《改善 C# 程序的157个建议》读书笔记
第三部分:编码规范及习惯;
[命名规范] [代码整洁] [规范开发行为]

标 [+] 的为需要注意的,或可以关注的;
标 [-] 的为个人不赞同的;

[+] 指示的是其下方的建议项。

第三部分 编码规范及习惯

第10章 命名规范

1. 命名空间与程序集 命名方式
  • 公司组织名称
    .



[+]

  • 使用域名(Java世界中常见)
    Com.Microsoft.

命名空间与程序集没有必然关系,
命名空间是逻辑分组;
程序集是物理分组;

2. 对于编译成 DLL 的程序集,建议命名空间与程序集名称一致。



[+]

3. 命名空间使用复数

另外,不要添加无意义前缀或后缀。
建议:System.Collections
不建议:System.Collection, System.AllCollections

4. 避免与 BCL 和 FCL 命名重复

BCL (Base Class Library)
FCL (Framework Class Library)



[+]

5. 类型命名:名词或名词词组

类型是现实中的实际对象,是名词。

动词:对象的行为,而不是类型本身。



[+]

6. 接口命名:形容词组

接口:Can Do; 表示具备某种能力。

7. 派生类使用基类名字做后缀

XxxException : Exception
XxxAttribute : Attribute
XxxEventArgs : EventArgs

8. 泛型使用 T 做前缀
9. 枚举

枚举类型:复数
枚举元素:单数

10. 公开元素:PascalCasing 命名
11. 考虑用类名作为属性名

public Company Company {get;set;}

12. 私有或局部变量:camelCasing 命名
13. 有条件地使用前缀

member : m
static : s

在变量较多时,可以谨慎考虑使用。
不过,变量较多时,考虑重构。



[+++]

14. 使用肯定性的短语命名布尔类型

前缀:Is Can Has …
好:IsChecked
坏:Checked

15. 使用后缀表示已有类型的新版本。

X509Certificate
X509Certificate2

不得不这样时,加后缀,而不是前缀,便于被发现。



[+]

16. 委托与事件类型应添加上后缀

XxxDelegate
XxxCallback
XxxEventHandler



[+]

17. 委托和事件变量使用动词或形容词短语命名

Click
SizeChanged
表示动作(委托)或事件的发生,状态的变化(事件)



[+]

18. 事件处理器(事件的订阅函数)或委托处理器命名

组合:
事件变量所属对象_事件变量名
委托变量所属对象On委托变量名

好:NameOnPropertyChanged
坏:NameChanged (看起来像事件的变量名)

第11章 代码整洁

1. 使用默认的访问修饰符

不是很赞同。
原因:添加默认的修饰符,如 internal class,是在显式声明这个类不应该被变成 public 的,
而不是忘记添加访问修饰符了。可以一定程度上防止他人随意修改访问权限。



[+++]

2. 不知道该不该用大括号,就用。

增加代码可读性。

下面的例子中,Resharper 等工具会提示 else 无需书写,以减少代码层级,但在这种情况下,
建议可以加上 else {},因为代码可读性明显提示。代码之间的关系和条理更清楚。

1
2
3
4
5
6
7
8
9
10
11
12
13
private bool Check()
{
if(xxx)
{
// ...
return true;
}
else
{
// ...
return false;
}
}
3. 总是使用有意义的命名。

同时,避免一心二意,同一个变量,在一段代码中应只表示一个含义。



[++]

4. 方法的抽象级别应在同一层级。

坏:

1
2
3
4
5
public void Init()
{
// xxx
RemoteInit();
}

这个例子中,Init 方法先进行了部分初始化工作,然后调用 RemoteInit 完成另一部分初始化工作。

好:

1
2
3
4
5
public void Init()
{
LocalInit();
RemoteInit();
}

建议的做法是,将两部分初始化工作都抽象为相同层级的方法(LocalInit 和 RemoteInit),在 Init 中调用。
层级更清晰。

5. (单一职责)一个方法只做一件事。

事情可大可小,但方法过长过负责时,就要考虑拆分。

6. (单一职责)避免过长的方法和过长的类。

过长的方法和过长的类是重构的首选目标。

7. (高内聚,最小知识)只对外公布必要的操作。
8. 重构多个相关属性为一个类。

e.g. 如一个 Person 类中,有地址,邮编,邮箱,电话,手机号等等属性,就应该考虑将其抽象为联系方式一个类。

9. 不重复代码



[+]

10. 使用表驱动法避免过长的 if 和 switch 分支。

使用字典、数组、索引等代替 if 和 switch 。
这个一种设计思路哦。

11. 使用匿名方法,Lambda 表达式代替方法。
12. 使用事件访问器替换公开的事件成员变量。

这个,C# 已经自动实现啦,无需考虑。



[-]

13. 最少,甚至是不要注释。

这个,不赞同。
写了注释不能成为代码本身糟糕的借口,但不代表不需要写注释,尤其是公开的方法,复杂的逻辑。
建议:保持代码本身的优雅,但不过分追求精简注释。

14. 如抛出异常,则必须要注释。

方法内部会抛出异常,在方法签名上方需要写注释。

1
2
3
4
5
6
7
8
9
10
/// <Summary>
/// 注释
/// </Summary>
/// <exception cref="System.IO.IOException">什么情况下会抛出该异常</exception>
public void Xxx()
{
// ...
throw new IOException("XXX");
}

第12章 规范开发行为



[+++]

1. 避免过度设计,在敏捷中重构

瀑布式开发:分析->设计->实现->测试。(试用与类似于建筑这样的”不可重构”的行业)缺点:不能很好地应对变化。
敏捷开发:关键词——迭代。(Spring)
敏捷使用“用户故事(User Story)”来核定需求和工作量。一个迭代提供一个完成的用户故事的实现,交付给客户(真实客户,或者测试部门,运营等。)



[+++]

2. 单元测试
  • TDD
  • 使用单元测试框架
3. 利用特性为应用程序提供多个版本

e.g. 条件编译
[Conditional(“ONLINE”)]
[Conditional(“OFFLINE”)]

4. 界面的自动化测试

工具:Code UI Automation


END