《Effective C#》快速筆記 - C# 高效編程要點補充 目錄 四十五、儘量減少裝箱拆箱 四十六、為應用程式創建專門的異常類 四十七、使用強異常安全保證 四十八、儘量使用安全的代碼 四十九、實現與 CLS 相容的程式集 五十、實現小尺寸、高內聚的程式集 這是這一系列的最後一篇。 四十五、儘量 ...
《Effective C#》快速筆記 - C# 高效編程要點補充
目錄
-
四十五、儘量減少裝箱拆箱
-
四十六、為應用程式創建專門的異常類
-
四十七、使用強異常安全保證
-
四十八、儘量使用安全的代碼
-
四十九、實現與 CLS 相容的程式集
-
五十、實現小尺寸、高內聚的程式集
這是該系列的最後一篇。也許有些理論有可能會過時,我想它仍有存在的必要,人的知識水平也是一個不斷成長的過程,學會站在前人的肩膀上,嘗試不斷的借鑒與總結。
四十五、儘量減少裝箱拆箱
-
值類型是數據的容器,不支持多態。
-
裝箱把一個值類型放在一個未確定類型的引用對象中,讓該值作為引用類型所使用。拆箱指從引用類型的位置取出值的一個副本。
-
裝箱和拆箱會在無意中創建許多副本,導致許多難以發現的 Bug。
-
使用介面而不是使用類型可以避免裝箱,即將值類型從介面實現,然後通過介面調用成員。
-
裝箱拆箱都是比較影響性能的手段,應該儘可能的避免裝拆箱操作。
-
泛型可以避免裝拆箱操作。
-
值類型裝箱是隱式的,難以發現,需要自己多加註意。
這裡是一篇較為詳細的關於裝拆箱的博文:《裝箱與拆箱》。
四十六、為應用程式創建專門的異常類
1.只有當用戶會以不同的形式去處理錯誤時,才應該創建不同的異常類。
2.自定義的異常類應該以“Exception”結尾,並且繼承 System.Exception 或其他異常類。不過你也需要適當地包含該基類中的構造函數,內容直接交給基類實現即可。
/// <summary> /// 自定義的異常類 /// </summary> public class MyException : Exception { public MyException() : base() { } public MyException(string s) : base(s) { } public MyException(string s, Exception e) : base(s, e) { } protected MyException(SerializationInfo info, StreamingContext cxt) : base(info, cxt) { } }
3.在拋出自定義的異常時,應該將原始的異常存放在 InnerException 屬性中,這樣就可以顯示足夠友好,並且信息豐富的異常:
public void Do() { try { //DoException(); } catch (DoException e) { var msg = $"該問題是博主故意引起的"; throw new MyException(msg, e); } }
4.只有在存在不同類型的恢復操作時,才應該拋出不同類型的異常,定義異常類時,還要提供基類中支持的所有構造函數。此外,不要忘記使用 InnerException 屬性來保存低層次的異常信息。
四十七、使用強異常安全保證
1.Dave Abrahams 定義了 3 種安全異常來保證程式:基礎保證、強保證,以及無拋出保證。
2.強異常保證:從異常中恢復和簡化異常處理之間提供了一個平衡點,如果一個操作因為某個異常中斷,程式將維持原狀態不變,操作要麼徹底完成,要麼就不會修改程式的任何狀態。強異常保證的好處:任何時候若是捕獲了異常,所有將要嘗試的正常操作都不繼續進行。程式當前的狀態如尚未開始進行該操作一樣。
3.對將要修改的數據做防禦性的複製,對這些數據的防禦性複製進行修改,這中間的操作可能會引發異常,在出現異常時可將臨時副本和原對象進行交換。
4.終結器、Dispose() 方法和委托對象所綁定的目標方法在任何情況下都應當確保他們不會拋出異常。
四十八、儘量使用安全的代碼
-
.NET 運行時可以保證一些懷有惡意的代碼不能直接滲透到遠程電腦上執行。
-
CLR 中的帶有代碼的訪問安全設置,如:CLR 強制要求基於角色的安全認證,這樣才能判斷某些代碼能否在基於一個特定的角色賬號下運行。
-
CLR 可以檢查 IL 代碼,確保它不存在潛在的危險行為。如:直接訪問原始記憶體。
-
如果代碼不需要任何的安全許可權,就不需要使用 CAS 的 API 來判斷訪問許可權,因為這樣只會影響性能,額外增加 CLR 的工作量。
-
你可以使用 CAS 的 API 來訪問一些受保護的資源,一般需要額外的許可權。如非托管的記憶體和文件系統、註冊表等。
-
一般來說,我們編寫的 C# 代碼都是安全的,除非你使用了 /unsafe。
-
應該儘可能地避免訪問非托管記憶體。確實有需要的話,應該將其隔離在獨立的程式集中。
四十九、實現與 CLS 相容的程式集
1..NET 運行環境與語言無關,我們創建的程式集必須與 CLS 保持相容,這樣才能保證其他的開發人員可以用另一種語言來調用你的組件。
五十、實現小尺寸、高內聚的程式集
-
如果我們都將所有的代碼放在一個程式集中,這不利於組件的重用,也不利於系統的局部更新,若是可以將其拆分成小程式集,以組件的形式進行重用,就可以從一定程度上簡化後續的開發工作。
-
我們用類進行功能的封裝和數據的存儲,只有公有的類、結構和介面才應該稱為契約,被其它用戶(或程式集)進行訪問。
-
建議將程式拆分成多個程式集,把相關的類型放在同一個程式集中。
-
一個程式集應該是一個包含相關功能的,具有良好組織的一個庫。如果不知道怎樣的顆粒度最好,可以略微向小而多的方向傾斜。
-
如果所有參數和返回值都是介面,那麼任何一個程式集都可以很容易地用另一個實現了相同介面的程式集進行代替。
-
更小的程式集同樣可以降低程式啟動時的開銷。更大的程式集要花上更多的 CPU 時間來載入,且需要更多的時間來將必須的 IL 編譯成機器指令。雖然只有啟動時將被調用的代碼會被 JIT 編譯,但程式集是整體載入的。
-
在跨越程式集時,安全性檢查會成為一個額外的開銷。程式跨越程式集的次數越小,其執行效率越高。
-
性能的損耗對我們來說可以忽略不計,因為在開發時,我們著重的是代碼的靈活度,所以不需要擔心將大程式集拆分成小程式集的性能問題。
-
常見的程式集:小且僅專註於某個特定功能的程式集,大一些但包含通用功能的程式集。無論何種情況,都應該保證其儘可能合理的小,但不應該過度。
本系列
《Effective C#》快速筆記(一)- C# 語言習慣
《Effective C#》快速筆記(二)- .NET 資源托管
《Effective C#》快速筆記(三)- 使用 C# 表達設計
《Effective C#》快速筆記(五) - C# 中的動態編程
《Effective C#》快速筆記(六) - C# 高效編程要點補充
【博主】反骨仔
【原文】http://www.cnblogs.com/liqingwen/p/6827546.html