以下為《編寫高質(zhì)量代碼:改善C#程序的157個(gè)建議》作者【陸敏技】的讀書總結(jié),添加了筆者自己的理解或示例。
90:不要為抽象類提供公開的構(gòu)造方法。abstract class MyAbstractClass{ protected MyAbstractClass(){}}
91:可見字段應(yīng)該重構(gòu)為屬性。public string Name { get; set; }。不過筆者認(rèn)為在快速迭代和大量使用屬性的情況下反而會(huì)降低工作效率。相比屬性來講,給成員起一個(gè)好名字更為重要。
92:謹(jǐn)慎將數(shù)組或集合作為屬性。如果是只讀屬性,會(huì)讓調(diào)用者產(chǎn)生歧義,因?yàn)殡m然是只讀,但是如果集合中的元素為引用類型,這個(gè)元素的內(nèi)部是可以更改的,不可更改的僅僅是集合持有對(duì)應(yīng)元素的引用。
93:構(gòu)造方法應(yīng)初始化主要屬性和字段。對(duì)初始化統(tǒng)一管理,避免遺忘,而且可以方便的看到初始化的數(shù)據(jù)是否過于龐大。
94:區(qū)別對(duì)待override和new,前者是覆蓋,后者是并存。
95:避免在構(gòu)造方法中調(diào)用虛成員。從而避免因override的存在而造成在父類初始化時(shí)調(diào)用子類的重寫函數(shù)。
96:成員應(yīng)優(yōu)先考慮公開基類型或接口。類型成員如果優(yōu)先考慮公開及類型或接口,那么會(huì)讓類型支持更多的應(yīng)用場(chǎng)合。例如泛型單例。
97:優(yōu)先考慮將基類型或接口作為參數(shù)傳遞。參考:里氏替換原則和面向接口編程
98:用params減少重復(fù)參數(shù)
99:重寫時(shí)不應(yīng)使用子類參數(shù),只使用跟本類相關(guān)職責(zé)的參數(shù)。
100:靜態(tài)方法和實(shí)例方法區(qū)別不大,靜態(tài)方法在加載時(shí)機(jī)和內(nèi)存使用上和實(shí)例方法完全一致,那它們之間唯一的區(qū)別就是,當(dāng)我們需要使用實(shí)例方法的時(shí)候,首先應(yīng)該有實(shí)例對(duì)象。
101:使用擴(kuò)展方法,向現(xiàn)有類型“添加”方法
102:區(qū)分接口和抽象類的應(yīng)用場(chǎng)合,前者為功能性添加,后者為通用性的歸納。
103:區(qū)分組合和繼承的應(yīng)用場(chǎng)合,組合優(yōu)于繼承。
104:用多態(tài)代替條件語句。參考策略模式
105:使用私有構(gòu)造函數(shù)強(qiáng)化單例。
106:為靜態(tài)類添加靜態(tài)構(gòu)造函數(shù)。使用靜態(tài)構(gòu)造方法的好處是,可以初始化靜態(tài)成員并捕獲在這過程中發(fā)生的異常。而使用靜態(tài)成員初始化器則不能在類型內(nèi)部捕獲異常了。
107:區(qū)分靜態(tài)類和單例。從本質(zhì)上講,在C#中,靜態(tài)類不會(huì)被認(rèn)為是一個(gè)“真正的對(duì)象”。而單例,則不會(huì)存在這樣的問題。單例,它是一個(gè)實(shí)例對(duì)象,僅僅因?yàn)樘厥獾囊?,它被自己?shí)現(xiàn)為在整個(gè)系統(tǒng)中只有一個(gè)對(duì)象。
108:將類型標(biāo)識(shí)為sealed,可以有效的防止使用者錯(cuò)誤的繼承
109:謹(jǐn)慎使用嵌套類
110:用類來代替enum,當(dāng)然僅僅是輕量值類型,使用enum毫無問題。
111:避免雙向耦合,也就是常說的互相持有、循環(huán)引用、孤島的循環(huán)引用。雖然C#使用的是可達(dá)算法避免這種互相引用造成的無法釋放GC的情況。但發(fā)現(xiàn)這種情況就應(yīng)該立刻重構(gòu)掉。
112:將現(xiàn)實(shí)世界中的對(duì)象抽象為類,將可復(fù)用對(duì)象圈起來就是命名空間
113:聲明變量前考慮最大值
114:MD5不再安全,例如暴力破解。
115:通過HASH來驗(yàn)證文件是否被篡改
116:避免用非對(duì)稱算法加密文件
117:使用SSL確保通信中的數(shù)據(jù)安全
118:使用SecureString保存密鑰等機(jī)密字符串
119:不要使用自己的加密算法。除非你對(duì)密碼學(xué)很在行
120:為程序集指定強(qiáng)名稱。(幾乎用不到)
121:為應(yīng)用程序設(shè)定運(yùn)行權(quán)限
122:以<Company>.<Component>為命名空間命名
123:程序集不必與命名空間同名
124:考慮在命名空間中使用復(fù)數(shù)
125:避免用FCL的類型名稱命名自己的類型
126:用名詞和名詞組給類型命名。類型定義了屬性和行為。雖然它包含行為,但不是行為本身。正確:OrderProcessor錯(cuò)誤:OrderProcess
127:用形容詞組給接口命名。接口規(guī)范的是“Can do”,也就是說,它規(guī)范的是類型可以具有哪些行為。所以,接口的命名應(yīng)該是一個(gè)形容詞,例如:IDisposable表示可以被釋放IEnumerable表示類型含有Items,可以被迭代。
128:考慮讓派生類的名字以基類名字作為后綴
129:泛型類型參數(shù)要以T作為前綴
130:以復(fù)數(shù)命名枚舉類型,以單數(shù)命名枚舉元素
131:用PascalCasing命名公開元素
132:考慮用類名作為屬性名。不過筆者更傾向前綴加Get
133:用camelCasing命名私有字段和局部變量
134:有條件地使用前綴,輕量使用。
135: 考慮使用肯定性的短語命名布爾屬性。public bool IsEnabled { get; set; }或public bool IsTabStop { get; set; }
136:優(yōu)先使用后綴表示已有類型的新版本,且SampleClass1比SampleClassNew要好,因?yàn)楹罄m(xù)可以添加為SampleClass2、SampleClass3等
137:委托和事件類型應(yīng)添加上級(jí)后綴
138:事件和委托變量使用動(dòng)詞或形容詞短語命名。例如:onClick
139:事件處理器命名采用組合方式。對(duì)象+下劃線+事件變量名,如:button_Click、button_SizeChanged、button_MouseDown。委托中的回調(diào),對(duì)象+On+委托變量名,如NameOnValidateValue,當(dāng)然如果處理器在類內(nèi)部,也可以是On+委托變量名。(筆者多數(shù)統(tǒng)一以O(shè)n對(duì)象Handle的形式,OnClickHandle)
140:使用默認(rèn)的訪問修飾符。筆者為了看上去統(tǒng)一,默認(rèn)的訪問修飾符也會(huì)添加。
141:不知道該不該用大括號(hào)時(shí),就用
142:總是提供有意義的命名。要知道讀代碼的時(shí)間要比寫代碼的所花費(fèi)的時(shí)間要多得多。
143:方法抽象級(jí)別應(yīng)在同一層次,可以理解為作用域的級(jí)別保持一致。
144:一個(gè)方法只做一件事
145:避免過長的方法和過長的類。對(duì)于方法在VS中需要滾屏才能閱讀完,那么就肯定有些過長了,必須想辦法重構(gòu)它。對(duì)于類型,除非有非常特殊的理由,類型的代碼不要超過300行。如果行數(shù)太多了,則要考慮是否重構(gòu)。
146:只對(duì)外公布必要的操作。因?yàn)檎{(diào)用者可能會(huì)調(diào)用他所能調(diào)用的所有元素且不分先后順序。
147:重構(gòu)多個(gè)相關(guān)屬性為一個(gè)類
148:不重復(fù)代碼。DRY原則
149:使用表驅(qū)動(dòng)法避免過長的if和switch分支,也就是有意義的變量最好用讀表的形式。
150:使用匿名方法、Lambda表達(dá)式代替方法。Linq+Lambda表達(dá)式真的很爽。拋棄易用性過分的追求極致性能,對(duì)目前的開發(fā)環(huán)境毫無意義。
151:使用事件訪問器替換公開的事件成員變量。(筆者保留意見)
152:最少,甚至是不要注釋。讓代碼自行解釋自身的行為。但絕不是說,添加注釋是一個(gè)錯(cuò)誤行為或者為自己不添加注釋找理由。
153:若拋出異常,則必須要注釋
154:不要過度設(shè)計(jì),在敏捷中體會(huì)重構(gòu)的樂趣。(夠用就好)
155:隨生產(chǎn)代碼一起提交單元測(cè)試代碼。
156:利用特性為應(yīng)用程序提供多個(gè)版本。例如Unity Debug輸出到屏幕并保存到本地中的Conditional("EnableLog")特性
157:從寫第一個(gè)界面開始,就進(jìn)行自動(dòng)化測(cè)試。