本文是读完前言中提到的几本书后,结合自身的想法总结出来的如何写好注释的一些比较实用的方法。
另外本文是上一篇 注释篇 的一个补充
如何写好注释
避免使用不明确的代词
有些情况下,"it", "this"等代词指代很容易产生歧义,最安全的方式是不要使用将所有可能产生歧义的代词替换成实际指代的词。
如://Insert the data into the cache,but check if it's too big first.
"it"是指"data"还是"cache"? 在读完剩下的代码前谁也不知道指代的是谁。那还要注释做什么?替换成要指代的词后读者就可以直接了当的知道接下来的代码要做什么了。
//Insert the data into the cache,but check if the data is too big first.
精确描述方法的行为
注释一定要精确的描述方法的行为。避免由于注释不准确而造成的误调用。
如你写了一个方法统计文件中的行数
//Return the number of lines in this file
public long CountLinesInFile(string fileName)
上面的注释不是很精确,因为有很多定义行的方式,下面几种情况这个方法的返回值无法根据注释快速的判断出来。
- ""(空文件)——0或1行?
- "hello"——0或1行?
- "hello\n"——1或2行?
- "hello\n\r world\r"——2、3或4行?
假设该方法的实现是统计换行符的(\n)的个数,下面的注释就要比原来的注释更好些。
//Count how many newline symbols('\n') are this file
这条注释包含更多的信息。读者可以知道如果没有换行符,这个函数会返回0。读者还知道回车符(\r)会被忽略。
用输入输出例子来说明特殊的情况
对于注释来讲,一个精挑细选的例子比千言万语还要有效,而且更加直白有效,阅读速度更快。
如: /// <summary>
/// Remove the suffix/prefix of charsToRemove from the input source
/// </summary>
public string StripPrefixAndSuffix(string source, string charsToRemove)
这条注释不是很精确,因为它不能回答下面的问题
- 是只有按charsToRemove中顺序的字符才会被移除,还是无序的charsToRemove也会被移除?
- 如果在开头和结尾有多个charsToRemove会怎样?
而一个好例子就可以简单直白的回答这些问题:
/// <summary>
/// Example: StripPrefixAndSuffix("abbayabbazbaba","ab") returns "yababz"
/// </summary>
适当的使用具名函数
假设你看见这样的函数调用:
ConnectMailServer(100,false);
因为直接传入的是数值和bool值,使得这个调用很难理解,在这种情况下可以使用C#的具名函数以便代码阅读者快速知道这两个参数的含意。
假设函数是这样的:public void ConnectMailServer(int timeout_s, bool useEncryption)
那我们可以这样使用具名函数:
ConnectMailServer(timeout_s: 100, useEncryption: false);
代码阅读者一眼就能看出这两个参数的作用。
使用通用专有名词
代码的阅读者和调用者都是程序员,程序员间有大量的专有名词可以用来描述一些模式和解决方案,使用这些词,可以简单明了的阐述你代码的含意。
假设你原来的注释是这样的:
那么你完全可以简单的说:
//This class acts as a caching layer to the database.
程序员一看caching layer就明白这个类是做什么的了。而且就算新手不明白,你的注释也很难给他讲明白的,还不如给他个关键词,让他自己去Google或向别人请教。这样的效果比你的注释会好的多。
更新代码时记得更新注释
再好的注释也会随着内容的更改而变得越来越没有意义,有时候甚至会对读者造成误导,产生不必要的bug。所以在更改代码后,记得要更新所更改代码的注释,使其表达最新代码的含意。
只有能让别人读懂的注释才是合格的注释
当自己不确定自己的注释是否合格时,请周围的同事读下你的注释,看他读完注释后说出的想法是否是你想要表达的,是否有信息遗漏和误解等。