《Effective C#》快速筆記(四)- 使用框架
.NET 是一個類庫,你了解的越多,自己需要編寫的代碼就越少。
目錄
- 三十、使用重寫而不是事件處理函數
- 三十一、使用 IComparable<T> 和 IComparer<T> 實現順序關系
- 三十二、避免使用 ICloneable 接口
- 三十三、僅用 new 修飾符處理基類更新
- 三十四、避免重載基類中定義的方法
- 三十五、PLINQ 如何實現並行算法
- 三十六、理解 PLINQ 在 I/O 密集場景
- 三十七、注意並行算法中的異常
三十、使用重寫而不是事件處理函數
1.處理系統之中觸發的事件:要么使用事件處理函數,要么重寫基類中的虛方法。在派生類中,你只應該重寫虛方法,而事件處理函數則應該使用在對象沒有關系的交互中。
2.從效率角度,重寫也比事件處理函數更快,事件處理器需要迭代整個請求列表,這樣占用了更多的CPU時間。
3.但是,事件是在運行時綁定的,因此會帶來更好的靈活性。
4.一個事件處理器拋出異常,則事件鏈上的其他處理器將不會被調用,而重寫的虛方法則不會出現這種情況。
5.重寫只能用於派生類中,其他類型必須使用事件機制。
三十一、使用 IComparable<T> 和 IComparer<T> 實現順序關系
1..NET 提供了兩個接口 IComparable<T> 和 IComparer<T> 表示順序關系。IComparable 定義了類型的自然順序,而 IComparer 則表示描述其他順序。
2.IComparable 接口包含一個方法:CompareTo() 。如果當前對象 < 被比較對象,返回值 < 0;當前對象 > 被比較對象,返回值 > 0;兩者相等,返回 0。
3.實現非泛型的 IComparable 接口的原因:保證向后兼容,反射中使用泛型會加大難度。
4.實現 IComparable 時請使用顯示接口實現,並提供一個強類型版本的重載,這個強類型的重載能提高性能,並降低使用者誤用 CompareTo 方法的可能。
三十二、避免使用 ICloneable 接口
1.當對象關系復雜時,深復制會帶來不必要的麻煩。
2.對於內建類型,如整數,深復制和淺復制的結果一樣。
3.內建的值類型不需要支持 ICloneable。賦值語句就可以復制結構中所有的值,且比 Clone() 更高效;而子類,僅在真正需要復制操作時再添加 ICloneable 支持。
4.對於值類型,永遠不要實現 ICloneable,直接使用賦值操作即可。
三十三、僅用 new 修飾符處理基類更新
1.new 修飾符必須小心謹慎的使用。如果它是有歧意的,就等於在類上創建了個模糊的方法。
2.只有在特殊情況下才使用,那就是升級基類時與你的類產生沖突時。即使在這種情況下,也應該小心的使用它。最重要的是,其它任何時候都不要用它。
三十四、避免重載基類中定義的方法
1.為基類中定義的方法創建重載增加了重載解析時的可選項,也就是增加了二義性。很可能你對重載選擇的理解和編譯期的解析並不相同,從而造成了用戶的困惑。解決辦法:選擇不同的名稱,因為這個類是你設計的,自然就可以給出更好,不同的的方法名稱。
2.不要重載那些定義於基類中的方法,這不能帶來絲毫意義,只能給使用者平添煩惱,但不針對重寫。
三十五、PLINQ 如何實現並行算法
1.使用時簡單的添加 AsParallel() 即可。
2.PLNQ 在能夠保證正確性的前提下,讓程序得到多核環境下的性能提升。
3.需要理解何時數據訪問是必須同步的,也需要衡量 ParallelEnumerable 中並行和順序版本方法帶來的影響。
4.PLINQ 無法並行化 LINQ to SQL 或 EF 的執行,因為這兩樣東西會借助數據庫引擎來執行並行查詢。
5.每個並行查詢都開始於一個分區的操作,PLINQ 需要對輸入元素分區,然后指派給負責執行查詢的任務。
6.4 種分區算法:單位分區、區塊分區、條帶分區和散列分區。
7.3 種其它算法:管道(Pipelining)、停止並進行(Stop&Go)和反向枚舉。
8.通過在查詢開始時添加 AsParallel() 方法,將查詢表達式轉換成並行執行。
var list = new List<int>(); var query=list.Where(x=>x<150).Select(x=>x.ToString()); //並行查詢 var queryParallel = list.AsParallel().Where(x => x < 150).Select(x => x.ToString());
三十六、理解 PLINQ 在 I/O 密集場景
var urls = new List<string>(); foreach (var url in urls) { var result = new WebClient().DownloadData(url); //發出一個同步的 Web 請求,然后等待接收數據,主要會將時間浪費在等待上 Console.WriteLine(result); } //使用並行處理模型 Parallel.ForEach(urls, url => { var result = new WebClient().DownloadData(url); Console.WriteLine(result); }); //使用 PLINQ var results = from url in urls.AsParallel() select new WebClient().DownloadData(url); results.ForAll(Console.Write);
1.PLINQ 的執行方式和並行任務庫的 Parallel.ForEach() 不同。PLINQ 使用固定數目的線程,而 Parallel.ForEach() 會調整線程的數量來增加吞吐量。
2.那些混合了 I/O 密集和 CPU 密集的操作來說,Parallel.ForEach() 更適合。Parallel.ForEach() 會根據當前的負載動態調整線程數量。當很多線程因為等待 I/O 操作而阻塞時,Parallel.ForEach() 會創建更多的線程提高吞吐量。當很多線程都在工作時,Parallel.ForEach() 也會限制活動線程的數量,降低上下文切換的代價。
3.對於那些需要訪問其他計算機,並等待遠程響應的程序來說,並行任務庫和 PLINQ 起到很重要的作用。
三十七、注意並行算法中的異常
1.后台線程中發生的異常會在不同的方面增加復雜度。異常不能穿過線程邊界保留調用棧,當異常傳遞到開始線程的方法時,線程就會中止。調用線程無法捕獲這個錯誤,也就不能進行對應的處理。
2.一旦后台線程拋出異常,其它的后台操作也會停止。最好是不要在並行算法中拋出異常。不過其它意料之外的異常也可能會出現。
本系列
《Effective C#》快速筆記(一)- C# 語言習慣
《Effective C#》快速筆記(二)- .NET 資源托管
《Effective C#》快速筆記(三)- 使用 C# 表達設計
《Effective C#》快速筆記(五) - C# 中的動態編程
《Effective C#》快速筆記(六) - C# 高效編程要點補充
【博主】反骨仔
【原文】http://www.cnblogs.com/liqingwen/p/6797709.html
【GitHub】https://github.com/liqingwen2015/XMind 可以下載 XMind
【參考】《Effective C#》