[.NET] 《Effective C#》快速筆記(四)- 使用框架


《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#》快速筆記(四) - 使用框架

  《Effective C#》快速筆記(五) - C# 中的動態編程

  《Effective C#》快速筆記(六) - C# 高效編程要點補充

 

 


【博主】反骨仔

【原文】http://www.cnblogs.com/liqingwen/p/6797709.html 

【GitHub】https://github.com/liqingwen2015/XMind 可以下載 XMind

【參考】《Effective C#》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM