本文章對書中 50 個做法進行總整理,以及對每個做法做出簡短總結,方便日後查看。
Chapter 1. C# Language Idioms
- 01.Prefer Implicitly Typed Local Variables : 使用 var 自動判斷型別,數值類型才需要明確宣告型別。
- 02.Prefer readonly to const :
確定要在編譯期間就將變數轉換成實際值才使用
const
,否則盡量使用readonly
宣告常數。 - 03.Prefer the is or as Operators to Casts :
優先使用
as
與is
進行轉型操作,特殊情況才用Cast expression
。 - 04.Replace string.Format with Interpolated Strings :
使用
String Interpolation
或StringBuilder
取代string.Format
可以獲得更好的效能,但不要用字串內插來寫 SQL 語法。 - 05.Prefer FormattableString for Culture-Specific Strings :
FormattableString
與一般的String
相比下更加彈性,可以用來處理多語系的功能。 - 06.Avoid String-ly Typed APIs :
弱型別的參數會帶來需多問題,建議改用
nameof()
在重構的時候會很有幫助。 - 07.Express Callbacks with Delegates :
講解 Delegate 的使用方法與建議使用內建的
Predicate<T>
、Action<T>
、Func<>
委派類型。 - 08.Use the Null Conditional Operator for Event Invocations :
使用
?
運算子檢查變數是否為 Null,事件處理EventHandler?.Invoke(this, e)
可讀性高也更加安全。 - 09.Minimize Boxing and Unboxing :
講解
Value Type
和Reference Type
的區別還有boxing
與unboxing
處理的流程。 - 10.Use the new Modifier Only to React to Base Class Updates :
在類別內使用
new
修飾詞需要小心,會導致基底類型與衍生類型的方法產生不一致的行為。
Chapter 2. .NET Resource Management
- 11.Understand .NET Resource Management :
講解
Managed Resource
、Unmanaged Resource
、Finalizer
相關知識。 - 12.Prefer Member Initializers to Assignment Statements :
建議在聲明變數的時候就直接初始化,使用
Initializers
,不僅寫起來比較直觀,在有多個建構函式的情況底下也很方便閱讀跟維護。 - 13.Use Proper Initialization for Static Class Members :
講解
static
基礎概念與靜態建構函式的用法,單例模式經常使用。 - 14.Minimize Duplicate Initialization Logic : 如果類別內有很多建構函式建議在建構函式後方接上 this 來減少建構函式的數量。
- 15.Avoid Creating Unnecessary Objects :
實例化參考型別背後會進行
Heap Allocation
,減少這個行為會改善軟體效能。 - 16.Never Call Virtual Functions in Constructors : 不要在底層類別的建構函式呼叫虛擬方法,會導致耦合並且執行的順序可能會與預測的不同。
- 17.Implement the Standard Dispose Pattern :
講解
IDisposable
概念與 Dispose Pattern 最佳實踐。
Chapter 3. Working with Generics
- 18.Always Define Constraints That Are Minimal and Sufficient : 講解泛型基本知識,與泛型約束的寫法。
- 19.Specialize Generic Algorithms Using Runtime Type Checking :
透過
as
與if
進行檢查與轉換,可以避免添加過多不必要的約束。 - 20.Implement Ordering Relations with IComparable
and IComparer : 講解如何實做IComparable<T>
與IComparer<T>
介面來達成排序的功能。 - 21.Always Create Generic Classes That Support Disposable Type Parameters :
在處理泛型類別時要時刻考慮傳入的參數的類型是否可能有
IDisposable
介面,有可能的話就需要在這個泛型類別中進行額外設計來避免記憶體流失。 - 22.Support Generic Covariance and Contravariance :
講解
Covariance
、Contravariance
、Invariant
的概念與使用in
、out
來達成這些能力。 - 23.Use Delegates to Define Method Constraints on Type Parameters : 建議用委派的方式來直接傳入方法,複雜的情況才用約束搭配建立新介面。
- 24.Do Not Create Generic Specialization on Base Classes or Interfaces : 如果類別內有泛型方法時最好不要再創建針對基底類別或介面的多載方法,因為可能會優先執行泛型的方法而不是需要再多一層轉換的多載方法。
- 25.Prefer Generic Methods Unless Type Parameters Are Instance Fields :
建議使用泛型方法除非需要將傳入的參數
T
建立為成員才使用泛型類別。 - 26.Implement Classic Interfaces in Addition to Generic Interfaces :
建議需要兼容舊版本的程式要同時實做泛型介面與一般介面,例如
IComparable<T>
與IComparable
。 - 27.Augment Minimal Interface Contracts with Extension Methods : 只在介面定義必要的方法,其它功能用擴充方法增強即可。
- 28.Consider Enhancing Constructed Types with Extension Methods :
可以幫
Close Generic Type
例如IEnumerable<int>
,建立擴充方法讓這些特殊型別跑專用的演算法。 - 29.Prefer Iterator Methods to Returning Collections :
講解
Iterator Methods
與yield return
能夠對效能帶來巨大的好處。
Chapter 4. Working with LINQ
- 30.Prefer Query Syntax to Loops :
建議使用 LINQ 的
Query Expression
取代基礎的迴圈操作。 - 31.Create Composable APIs for Sequences :
講解能夠將多個
Iterator Methods
進行串聯的特性能夠提升閱讀性。 - 32.Decouple Iterations from Actions, Predicates, and Functions :
使用內建的
Predicate<T>
、Action<T>
、Func<>
搭配Iterator Methods
將不屬於方法的職責移出去來達到解耦的效果。 - 33.Generate Sequence Items as Requested :
講解
Iterator Methods
的Lazy Evaluation
特性,等待真正需要用到值的時候才會執行該方法。 - 34.Loosen Coupling by Using Function Parameters :
講解在
Iterator Methods
使用委派當作參數來解耦,以及與抽象及介面的解耦進行相比。 - 35.Never Overload Extension Methods :
講解切換
using namespace
來多載擴充方法是非常不好的做法。 - 36.Understand How Query Expressions Map to Method Calls :
講解
query expression pattern
定義的 11 個方法,以及它們背後轉換成Method Call
的邏輯。 - 37.Prefer Lazy Evaluation to Eager Evaluation in Queries :
講解特殊場合可以使用
ToList()
或ToArray()
從Lazy Evaluation
換成Eager Evaluation
。 - 38.Prefer Lambda Expressions to Methods : 建議建立包含多個小的查詢語句靜態擴充方法來共用重複邏輯,而不是寫一個本地方法。
- 39.Avoid Throwing Exceptions in Functions and Actions :
不要在
Action
與Func
拋出錯誤否則會導致數據錯亂,並建議可以用ToList()
建立臨時備份等到完全成功在覆蓋回原變數。 - 40.Distinguish Early from Deferred Execution : 講解提前執行與延遲執行該如何挑選,關鍵要確保兩種執行方式都能有同樣的結果。
- 41.Avoid Capturing Expensive Resources :
講解
Closure
在 C# 中是如何產生出來的,以及要避免Closure
把昂貴的資源捕捉進去來避免記憶體流失。 - 42.Distinguish between IEnumerable and IQueryable Data Sources : 講解 IEnumerable 與 IQueryable 背後執行的原理和它們使用的場合。
- 43.Use Single and First to Enforce Semantic Expectations on Queries :
講解 LINQ 常用的讀取元素的擴充方法
Single
、First
、Last
、SingleOrDefault
、FirstOrDefault
、LastOrDefault
- 44.Avoid Modifying Bound Variables :
講解
Closure
是如何達成變數捕捉的效果,以及避免修改被捕捉的變數。
Chapter 5. Exception Practices
- 45.Use Exceptions to Report Method Contract Failures :
建議雙方都有共識的程式碼不用拋出錯誤應該要注重的是事後的處理過程,而非共識的地方才考慮拋出
Exception
。 - 46.Utilize using and try/finally for Resource Cleanup :
講解使用
using
來釋放記憶體的重要性,以及可以直接使用try/final
實現自己的釋放流程。 - 47.Create Complete Application-Specific Exception Classes :
只有事後需要特殊處理的錯誤才考慮建立客製化的
Exception
。 - 48.Prefer the Strong Exception Guarantee :
詳細說明三種
Exception Guarantee
各自的定義以及使用場合。 - 49.Prefer Exception Filters to catch and re-throw :
說明
Exception Filters
與when
子句的使用方式,建議可以用來取代舊有寫在Exception
內部的邏輯判斷之後拋出的流程。 - 50.Leverage Side Effects in Exception Filters :
講解
Exception Filters
會優先執行判斷邏輯的特性,並利用它來做到安插監控程式碼的效果。