《Effective C#》快速筆記(三)- 使用 C# 表達設計 目錄 二十一、限制類型的可見性 二十二、通過定義並實現介面替代繼承 二十三、理解介面方法和虛方法的區別 二十四、用委托實現回調 二十五、用事件模式實現通知 二十六、避免返回對內部類對象的引用 二十七、讓類型支持序列化 二十八、提供組 ...
《Effective C#》快速筆記(三)- 使用 C# 表達設計
目錄
- 二十一、限制類型的可見性
- 二十二、通過定義並實現介面替代繼承
- 二十三、理解介面方法和虛方法的區別
- 二十四、用委托實現回調
- 二十五、用事件模式實現通知
- 二十六、避免返回對內部類對象的引用
- 二十七、讓類型支持序列化
- 二十八、提供組粒度的網際網路服務 API
- 二十九、支持泛型協變和逆變
二十一、限制類型的可見性
1.在保證類型可以完成工作的前提下,應該儘可能地給類型分配最小的可見性。
2.我們經常下意識的創建公有類型。可見性越低,以後升級或更改時所需要的變化就越小,因為能訪問你功能模塊的代碼越少。
3.創建內部類是一種常被忽略限制類型作用域的做法,我們經常習慣不假思索地創建公有類。你應該仔細思考這個一個類型的作用範圍,即它是將被所有的客戶使用,還是僅用在這個程式集的內部。
4.更少的公有類型可以減少單元測試的數量。
5.以公有形式暴露給外界的類和介面將成為你的組件的契約。介面越冗餘,日後的修改就越受限。暴露的公有類型越少,以後更新擴展的時候周旋的餘地就會越大。
二十二、通過定義並實現介面替代繼承
1.抽象基類為類的繼承體系提供了一個共用的祖先,介面描述了一組原子性的功能。介面是一種契約,抽象基類則為一組相關的類型提供了一個共用的抽象。基類描述了對象是什麼,介面描述了對象如何表現它的行為。
2.我們可以將可重用的行為提取出來,定義在介面中。由於不相關的類型均可以實現一個介面,這表示代碼的重用率將大大增加。
3.如果向基類中添加一個方法,所有派生類都將自動包含該方法。也就是說,隨著時間的推移,仍可以有效擴展多個類型功能的途徑。通過向基類添加並實現某種功能,所有的派生類都將立即擁有該功能。而向介面中添加一個成員,會破壞所有實現該介面的類。因為這些類不包含新方法,每一個實現都需要進行更新,然後重新編譯。
4.在抽象基類和介面之間做選擇,實際上就表示了對日後可能發生變化的不同處理態度。介面是固定的:我們將一組功能封裝在一個介面,作為其他類型的契約。而基類則可以在日後擴展,這些擴展也會成為每個派生類的一部分。
5.也可以使用擴展方法進行擴展。
public static class Extendsions { public static void ForAll<T>(this IEnumerable<T> sequence, Action<T> action) { foreach (var item in sequence) { action(item); } } }
方法調用:
IEnumerable<object> objects = new List<string>(); objects.ForAll(x => Console.WriteLine(x)); objects.ForAll(Console.WriteLine);
6.有時候,使用介面可以幫助我們避免 struct 類型的拆箱所帶來的代價。
二十三、理解介面方法和虛方法的區別
1.在基類中實現一個介面時,派生類需要使用 new 來隱藏對基類方法的使用。
2.可以將基類介面的方法申明為虛方法,然後在派生類中實現。
二十四、用委托實現回調
1.類之間需要通信時,並且我們期望一種比介面所提供的更為鬆散的耦合機制時,委托就是最佳的選擇。
2.多播委托會把所有添加到該委托中的目標函數組合成一個單一的調用。需要註意的是:
(1)如果有委托調用出現異常,那麼就不能保證安全;
(2)整個調用的返回值將為最後一個函數調用的返回值。
3.在多播委托調用的過程中,每個目標會被依次調用。委托對象本身不會捕捉任何異常。因此,任何目標拋出的異常都會結束委托鏈的調用。
二十五、用事件模式實現通知
1..NET 中的事件就是觀察者模式的一個語法上的快捷實現。
2.使用 System.ComponentModel.EventHandlerList 容器來存儲各個事件處理器,在類型中包含大量事件時可以使用他來隱藏所有事件的複雜性。
3.EventHandlerList並沒有提供內建的泛型實現,可以自行基於 Dictionary 構建。
二十六、避免返回對內部類對象的引用
1.4 種策略可以防止類型的內部數據結構遭受有意或無意的修改:值類型、常量類型、介面和包裝器(wrapper):
(1)當客戶代碼通過屬性來訪問值類型成員時,實際返回的是值類型的副本。
(2)常量類型,如:System.String 也是安全的。
(3)通過介面向外界暴露類的功能,即可儘量地避免內部數據遭受無意的更改,定義介面將訪問限制在一個子集中從而最小化對對象內部狀態的破壞。
(4)僅暴露包裝器,定義一個包裝器對象來限制另一個對象的訪問。
2.通過使用介面、包裝器對象或值類型向外界提供內部的私有數據,即可限制外界對這些數據的訪問能力。
二十七、讓類型支持序列化
1.[Serializable] 特性支持序列化。
2.[NonSerialized] 特性阻止序列化。
二十八、提供組粒度的網際網路服務 API
1.程式中最耗時的是與遠程伺服器之間的數據傳輸,每次通過網路獲取一小段數據時,應用程式都需要等待網路傳輸的過程,API 的粒度越細,所花費在等待數據返回上的額外時間也就越多。
2.我們希望同時降低通信的頻率以及每次通信時所傳遞的數據量。但這兩個目標往往不可兼得,因此必須做出取捨。儘量不要走兩個極端,可以適當選擇較少的通信次數,儘量一次傳輸更多的數據。
二十九、支持泛型協變和逆變
1.類型變體:協變和逆變。定義了在某種情況下,某個類型可以代替另一個類型進行使用。若不能將一個類型替換成另一個,則這個類型就叫不變數,在 C# 4.0 之前,所有泛型類型都不變數。你應該儘可能地讓泛型介面和泛型委托支持協變和逆變。
2.協變和逆變是兩種不同形式的類型替換。若某個返回的類型可以由派生類型替換,那麼這個類型就是支持協變的。若某個參數類型可以由其基類替換,那麼這個類型就是支持逆變的。
3.在可能的情況下為泛型介面和委托添加上 in 和 out 參數進行修飾。
4.因為 IList<T> 沒有添加 in 或 out 修飾 T,所以必須使用精確的類型匹配。
本系列
《Effective C#》快速筆記(一)- C# 語言習慣
《Effective C#》快速筆記(二)- .NET 資源托管
《Effective C#》快速筆記(三)- 使用 C# 表達設計
【博主】反骨仔
【原文】http://www.cnblogs.com/liqingwen/p/6774210.html
【參考】《Effective C#》