[.NET] 《Effective C#》快速筆記(一)- C# 語言習慣

《Effective C#》快速筆記(一)- C# 語言習慣

 

目錄

  • 1、使用屬性而不是可訪問的數據成員
  • 2、使用運行時常量(readonly)而不是編譯時常量(const)
  • 3、推薦使用 is 或 as 操做符而不是強制類型轉換
  • 4、使用 Conditional 特性而不是 #if 條件編譯
  • 5、爲類型提供 ToString() 方法
  • 6、理解幾個等同性判斷之間的關係
  • 7、理解 GetHashCode() 的陷阱
  • 8、推薦使用查詢語法而不是循環
  • 9、避免在 API 中使用轉換操做符
  • 10、使用可選參數減小方法重載的數量
  • 11、理解短小方法的優點

 

1、使用屬性而不是可訪問的數據成員

 

2、使用運行時常量(readonly)而不是編譯時常量(const)

  1. C# 有兩種類型的常量:編譯時常量和運行時常量。html

  2.儘可能使用運行時常量,而不是編譯時常量。編程

        /// <summary>
        /// 編譯時常量
        /// </summary>
        public const int Num = 100;

        /// <summary>
        /// 運行時常量
        /// </summary>
        public static readonly int Year = 2017;

  3.編譯時常量只能用於數字和字符串,運行時常量也是一種常量,由於在構造函數執行後它不能被再次修改。安全

  4.const 比 readonly 效率高,但靈活性低。框架

 

3、推薦使用 is 或 as 操做符而不是強制類型轉換

  1.as 比強轉更加高效、安全。函數

  2.as 操做符不能配合值類型使用,由於值類型永遠不可能爲 null。post

 

4、使用 Conditional 特性而不是 #if 條件編譯

        public static void Test()
        {
            string msg = null;

            #if DEBUG
            msg = "Hi";
            #endif

            Console.WriteLine(msg);
        }

  假如你是將這塊代碼在 Release 版本中執行的話,就會輸出空行。出現 Bug 的緣由是咱們把程序中的主要邏輯代碼和條件編譯代碼混在一塊了。這會讓咱們很難察覺不一樣版本間的差別,致使錯誤的行爲發生。優化

 

5、爲類型提供 ToString() 方法

  1.應該爲類型提供一個合適的 ToString() 版本,不然使用者會根據類的一些屬性來自行構造並用於顯示。ui

  2.object 默認提供的 ToString() 方法會返回類型的完整名稱,意義不大。如:System.Drawing.Rect。spa

  3.重寫全部類型的 ToString(),能夠簡單明瞭的顯示對象的摘要信息。設計

 

6、理解幾個等同性判斷之間的關係

  1.系統提供 4 種函數判斷兩個對象是否「相等」。

  2.對於前兩種方法,咱們永遠不要從新定義,咱們一般要重寫 Equals 方法。

  3.重寫 Equals 的類型也要實現 IEquatable<T>,若是是結構體的話須要實現 IStructuralEquatable。

  4.引用同一個 DataRow,會認爲相等,若是想比較內容的話,而不是引用地址,那麼就應該重寫 Equals() 實例方法。

  5.Equals() 實例方法的重寫原則:對於全部的值類型,都應該重寫 Equals() 方法,對於引用類型,若是不能知足須要時纔去重寫該方法。重寫該方法的同時也須要重寫 GetHashCode() 方法。

  6.operator == ():只要建立的是值類型,都必須從新定義 operator == (),由於系統默認是經過反射來比較兩個值是否相等,效率太低。

 

7、理解 GetHashCode() 的陷阱

  1.對於咱們實現的大多數類型來講,避免實現 GetHashCode()。

  2.GetHashCode() 的重載版本必須遵循如下三條原則:

  (1)若是兩個對象相等(由 operator == 定義),那麼它們必須生成相同的散列碼。

  (2)對於任何一個對象 A,A.GetHashCode() 必須保持不變。

  (3)對於全部的輸入,散列函數應該在全部整數中按照隨機分佈生成散列碼。

 

8、推薦使用查詢語法而不是循環

  示例:

            //1.使用循環
            var foo = new int[100];

            for (int i = 0; i < 100; i++)
            {
                foo[i] = i * i;
            }

            //使用查詢語法
            var foo2 = (from n in Enumerable.Range(0, 100) select n * n).ToArray();

  1.有些方法語法沒有對應的查詢語法,如 Take、TaskWhile、Skip、SkipWhile、Min、Max 等,就須要使用方法語法。

 

9、避免在 API 中使用轉換操做符

 

10、使用可選參數減小方法重載的數量

  1.對於程序集的第一次發佈,能夠隨意使用可選參數和命名參數。而在進行後續發佈時,必須爲額外的參數建立重載。這樣才能保證如今的程序仍能正常運行。此外,在任何的後續發佈中,都要避免修改參數的名稱,由於參數名稱已經成爲公有接口的一部分。

 

11、理解短小方法的優點

  1.咱們最好儘量地編寫出最清晰的代碼,將優化工做交給 JIT 完成。一個常見的錯誤優化是,咱們將大量的邏輯放在一個函數中,覺得這樣能夠減小額外的方法調用開銷。

        public string Test(bool isTrue)
        {
            var sb = new StringBuilder();

            if (isTrue)
            {
                sb.AppendLine("A");
                sb.AppendLine("B");
                sb.AppendLine("C");
            }
            else
            {
                sb.AppendLine("E");
                sb.AppendLine("F");
                sb.AppendLine("G");
            }

            return sb.ToString();
        }

  在第一次調用 Test 方法時, if-else 的兩個分支都被 JIT 編譯,而實際上只須要編譯其中一個,修改後:

        public string Test2(bool isTrue)
        {
            var sb = new StringBuilder();

            if (isTrue)
            {
                return Method1();
            }
            else
            {
                return Method2();
            }
        }

  如今進行了方法拆分,這兩個方法就能夠根據須要進行 JIT 編譯,而沒必要第一次進行所有編譯。

  2.能夠將 if-else 分支中有超過幾十條的語句,或者某個分支專門用來處理程序發生的錯誤,或者 switch 語句中的每一個 case 中的代碼進行選擇性的提取。

  3.短小精悍的方法(通常包含較少的局部變量)會讓 JIT 更容易地進行寄存器選擇工做,即選擇哪些局部變量放在寄存器中,而不是棧上。

  4.儘可能編寫短小精悍的方法。

 

本系列

  《Effective C#》快速筆記(一)- C# 語言習慣

  《Effective C#》快速筆記(二)- .NET 資源託管

  《Effective C#》快速筆記(三)- 使用 C# 表達設計

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

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

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

 


【博主】反骨仔

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

【參考】《Effective C#》

相關文章
相關標籤/搜索