《Effective C#中文版:改善C#程式的50種方法》讀書筆記 

來源:互聯網
上載者:User
來自: http://kb.cnblogs.com/page/106722/

    從去年找工作以來,都沒什麼時間寫部落格[找工作的體會:建議以後有自己開公司的IT人一定要找IT專業人員做HR,好多公司的HR並不能真正發掘人 才,他們形成了太多的偏見,如在學校期間學不了什麼東西、只看學校有多少獎勵等。真正鑽研技術的人才不會追求虛無的東西],其實這本書我都借了好久,一直 沒有系統的看,所以趁這兩天好好看看,順便總結了一些要點,給那些需要這方面知識而又沒有太多時間的IT人一個快速的學習機會。。。。如果要深入學習,請 購買該書。
  一、用屬性代替可訪問的欄位

  1、.NET資料繫結只支援資料繫結,使用屬性可以獲得資料繫結的好處;

  2、在屬性的get和set訪問器重可使用lock添加多線程的支援。

  二、readonly(運行時常量)和const(編譯時間常量)

  1、const只可用於基元類型、枚舉、字串,而readonly則可以是任何的類型;

  2、const在編譯時間將替換成具體的常量,這樣如果在引用中同時使用了const和readonly兩種值,則對readonly的再次改變將會改變設計的初衷,這是需要重新編譯所更改的程式集,以重新引用新的常量值。

  3、const比readonly效率高,但失去了應用的靈活性。

  三、is與as

  1、兩者都是在運行時進行類型的轉換,as操作符只能使用在參考型別,而is可以使用值和參考型別;

  2、通常的做法是用is判斷類型,然後選擇使用as或強型別轉換操作符(用operater定義的轉換)有選擇地進行。

  四、ConditionalAttribute代替#if #endif條件編譯

  1、ConditionalAttribute只用於方法級,對其他的如類型、屬性等的添加都是無效的;而#if #endif則不受此限制;

  2、ConditionalAttribute可以添加多個編譯條件的或(OR)操作,而#if #endif則可以添加與(AND)[這裡可以完全定義為另一個單獨的符號];

  3、ConditioanlAttribute定義可以放在一個單獨的方法中,使得程式更為靈活。

  五、提供ToString()方法

  1、可以更友好的方式提供使用者詳細的資訊;

  2、使用IFormatter.ToString()方法提供更靈活的定製,如果添加IFormatProvider 和ICustomFormatter介面則更有意義的定製訊息輸出。

  六、值和參考型別的區別

  1、實值型別不支援多態,適合儲存應用程式操作的資料,而引用則支援多態,適用於定義應用程式的行為;

  2、對於數組定義為實值型別可以顯著提高程式的效能;

  3、實值型別具有較少的堆記憶體片段、記憶體垃圾和間接訪問時間,其在方法中的返回是以複製的方式進行,避免暴露內部結構到外界;

  4、實值型別應用在如下的情境中:類型的職責主要是用於資料存放區;公用介面完全由一些資料成員存取屬性定義;永遠沒有子類;永遠沒有多態行為。

  七、實值型別儘可能實現為常量性和原子性的類型

  1、使我們的代碼更易於編寫和維護;

  2、初始化常量的三種策略:在構造中;Factory 方法;構造一個可變的輔助類(如StringBuilder)。

  八、確保0為值得有效狀態

  1、實值型別的預設狀態應為0;

  2、枚舉類型的0不應為無效的狀態;在FlagsAttribute是應確保0值為有效地狀態;

  3、在字串為為空白時可以返回一個string.Empty的Null 字元串。

  九、相等判斷的多種表示關係

  1、ReferenceEquals()判斷引用相等,需要兩個是引用同一個對象時方可返回true;

  2、靜態Equals()方法先進行引用判斷,再進行實值型別判斷的;

  3、對於參考型別的判斷可以在使用值語義時使用重寫Equals()方法;

  4、重寫Equals()方法時也應當重寫GetHashCode()方法,同時提供operater==()操作。

  十、理解GetHashCode()方法的缺陷

  1、GetHashCode()僅應用在基於散列的集合定義鍵的散列值,如HashTable或Dictionary;

  2、GetHashCode()應當遵循相應的三條規則:兩個相等對象應當返回相同的散列碼;應當是一個執行個體不變式;散列函數應該在所有的整數中產生一個隨機的分布。

  十一、優先使用foreach迴圈語句

  1、foreach可以消除編譯器對for迴圈對數組邊界的檢查;

  2、foreach的迴圈變數是唯讀,且存在一個顯式的轉換,在集合對象的物件類型不正確時拋出異常;

  3、foreach使用的集合需要有:具備公有的GetEnumberator()方法;顯式實現了IEnumberable介面;實現了IEnumerator介面;

  4、foreach可以帶來資源管理的好處,因為如果編譯器可以確定IDisposable介面時,可以使用最佳化的try…finally塊;

  十二、預設欄位的初始化優於指派陳述式

  1、欄位生命預設會將實值型別初始化為0,參考型別初始化為null;

  2、對同一個對象進行多次初始化會降低代碼的執行效率;

  3、將欄位的初始化放到構造器中有利於進行異常處理。

  十三、使用靜態構造器初始化靜態成員

  1、靜態構造器會在一個類的任何方法、變數或者屬性訪問之前執行;

  2、靜態欄位同樣會在靜態構造器之前運行,同時靜態構造器有利於異常處理。

  十四、利用構造器鏈(在.NET 4.0已經用選擇性參數解決了這個問題)

  1、用this將初始化工作交給另一個構造器,用base調用基類的構造器;

  2、類型執行個體的操作順序是:將所有的靜態欄位都設定為0;執行靜態欄位初始化器;執行基類的靜態構造器;執行當前類型的靜態構造器;

  將所有的執行個體欄位設定為0;執行執行個體欄位初始化器;執行合適的基類執行個體構造器;執行當前類型的執行個體構造器。

  十五、利用using和try/finally語句來清理資源

  在IDisposable介面的Dispose()方法中用GC.SuppressFinalize()可通知垃圾收集器不再執行終結操作。

  十六、盡量減少記憶體垃圾

  1、分配和銷毀一個堆上的對象都要花費額外的處理器時間;

  2、減少指派至數量的技巧:經常使用的局部變數提升為欄位;提供一個類,用於儲存Singleton對象來表達特定類型的常用執行個體。

  3、用StringBuilder進行複雜的字串操作。

  十七、盡量減少裝箱和拆箱

  1、關注一個類型到System.Object的隱式轉換,同時實值型別不應該被替換為System.Object類型;

  2、使用介面而不是使用類型可以避免裝箱,即將實值型別從介面實現,然後通過介面調用成員。

  十八、實現標準Dispose模式

  1、使用非記憶體資源,它必須有一個終結器,垃圾收集器在完成沒有終結其的記憶體對象後,會將實現了終結器對象的添加到終結隊列中,然後垃圾收集器會啟動 一個新的線程來運行這些對象上的終結器,這種防禦性的變成方式是因為如果使用者忘記了調用Dispose()方法,記憶體回收行程總是會調用終結器方法的,這樣 可以避免出現非託管的記憶體資源不被釋放引起記憶體流失的問題;

  2、使用IDisposable.Dispose()方法需要做四個方面的工作:釋放所有的非託管資源;釋放所有的託管資源;設定一個狀態標記來表示是否已經執行了Dispose();調用GC.SuppressFinalize(this)取消對象的終結操作;

  3、為需要多態的類型添加一個受保護的虛方法Dispose(),衍生類別通過重寫這個方法來釋放自己的任務;

  4、在需要IDisoposable介面的類型中,即使我們不需要一個終結器也應該實現一個終結器。

  十九、定義並實現介面優於繼承類型

  1、不相關的類型可以共同實現一個共同的介面,而且實現介面比繼承更容易;

  2、介面比較穩定,他將一組功能封裝在一個介面中,作為其他類型的實現合約,而基類則可以隨著時間的推移進行擴充。

  二十、明辨介面實現和虛方法重寫

  1、在基類中實現一個介面時,衍生類別需要使用new來隱藏對基類方法的使用;

  2、可以將基類介面的方法申明為虛方法,然後再衍生類別中實現。

  二十一、使用委託表達回調

  1、委派物件本身不提供任何異常捕獲,所以任何的多播委託調用都會結束整個調用鏈;

  2、通過顯示調用委託鏈上的每個委託目標可以避免多播委託僅返回最後一個委託的輸出。

  二十二、使用事件定義外部介面

  1、應當聲明為共有的事件,讓編譯器為我們建立add和renmove方法;

  2、使用System.ComponentModel.EventHandlerList容器來儲存各個事件處理器,在類型中包含大量事件時可以使用他來隱藏所有事件的複雜性。

  二十三、避免返回內部類對象的引用

  1、由於實值型別對象的訪問會建立一個該對象的副本,所以定義一個實值型別的的屬性完全不會改變類型對象內部的狀態;

  2、常量類型可以避免改變對象的狀態;

  3、定義介面將訪問限制在一個子集中從而最小化對對象內部狀態的破壞;

  4、定義一個封裝器對象來限制另一個對象的訪問;

  5、希望客戶代碼更改內部資料元素時可以實現Observer模式,以使對象可以對更改進行校正或相應。

  二十四、聲明式編程優於命令式編程

  可以避免在多個類似的手工編寫的演算法中犯錯誤的可能性,並提供清晰和可讀的代碼。

  二十五、儘可能將類型實現為可序列化的類型

  1、類型表示的不是UI控制項、視窗或者表單,都應使類型支援序列化;

  2、在添加了NonSerializedAttribute的還原序列化的屬性時可以通過實現IDeserializationCallback的OnDeserialization()方法裝入預設值;

  3、在版本控制中可以使用ISerializable介面來進行靈活的控制,同時提供一個序列化的構造器來根據流中的資料初始化對象,在實現時還要求SerializationFormatter異常的許可;

  4、如果需要建立衍生類別則需要提供一個掛鈎方法供衍生類別使用。

  二十六、使用IComparable和IComparer介面實現排序關係

  1、IComparable介面用於為類型實現最自然的排序關係,重載四個比較操作符,可以提供一個重載版的CompareTo()方法,讓其接受具體類型作為參數;

  2、IComparer用於提供有別於IComparable的排序關係,或者為我們提供類型本身說沒有實現的排序關係。

  二十七、避免ICloneable介面

  1、對於實值型別永遠不需要支援ICloneable介面,使用預設的賦值操作即可;

  2、對於可能需要支援ICloneable介面的基類,應該為其創造一個受保護的複製構造器,並應當避免支援IConeable介面。

  二十八、避免強制轉換操作符

  通過使用構造器來代替轉換操作符可以使轉換工作變得更清晰,由於在轉換後使用的臨時對象,容易導致一些詭異的BUG。

  二十九、只有當新版積累導致問題時才考慮使用new修飾符  三十、儘可能實現CLS相容的程式集

  1、建立一個相容的程式集需要遵循兩條規則:程式集中所有公有和受保護的成員所使用的參數和傳回值類型都必須與CLS相容;任何與CLS不相容的公有和受保護的成員都必須有一個與CLS相容的替代品;

  2、可以通過顯式實現介面來避開CLS相容類型檢查,及CLSCompliantAttribute不會檢查私人的成員的CLS相容性。

  三十一、儘可能實現短小簡潔的方法

  1、JIT編譯器以方法為單位進行編譯,沒有被調用的方法不會被JIT編譯;

  2、如果將較長的Switch中的Case語句的代碼替換成一個一個的方法,則JIT編譯器所節省的時間將成倍增加;

  3、短小精悍的方法並選擇較少的局部變數可以獲得最佳化的寄存器使用;

  4、方法內的控制分支越少,JIT編譯器越容易將變數放入寄存器。

  三十二、儘可能實現小尺寸、高內聚的程式集

  1、將所有的公有類以及共用的基類放到一些程式集中,把為公有類提供功能的工具類也放入同樣的程式集中,把相關的公有介面打包到他們自己的程式集中,最後處理遍布應用程式中水平位置的類;

  2、原則上建立兩種組件:一種為小而彙總、具有某項特定功能的程式集,另一種為大而寬、包含共用功能的程式集。

  三十三、限制類型的可見度

  1、使用介面來暴露類型的功能,可以使我們更方便地建立內部類,同時又不會限制他們在程式集外的可用性;

  2、向外暴露的公有類型越少,未來擴充和更改實現所擁有的選擇就越多。

  三十四、建立大粒度的Web API

  這是在機器之間的交易的頻率和載荷都降到最低,將大的操作和細粒度的執行放到伺服器執行。

  三十五、重寫優於事件處理器

  1、一個事件處理器拋出異常,則事件鏈上的其他處理器將不會被調用,而重寫的虛方法則不會出現這種情況;

  2、重寫要比關聯事件處理器高效得多,事件處理器需要迭代整個請求列表,這樣佔用了更多的CPU時間;

  3、事件能在運行時響應,具有更多的靈活性,可以對同一個事件關聯多個響應;

  4、通行的規則是處理一個衍生類別的事件是,重寫方式較好。

  三十六、合理使用.NET運行時診斷

  1、System.Diagnostics.Debug\Trace\EventLog為運行時提供了程式添加診斷資訊所需要的所有工具,EventLog提供入口時的應用程式能寫到系統事件日誌中;

  2、最後不要寫自己的診斷庫,.NET FCL 已經擁有了我們需要的核心庫。

  三十七、使用標準配置機制

  1、.NET架構的System.Windows.Application類為我們定義了建立通用配置路徑的屬性;

  2、Application.LocalAppDataPath 和 Application.userDataPath 會產生本機資料目錄和使用者資料的路徑名;

  3、不要在ProgramFiles和Windows系統目錄中寫入資料,這些位置需要更高的安全許可權,不要指望使用者擁有寫入的許可權。

  三十八、定製和支援資料繫結

  1、BindingMananger和CurrencyManager這兩個對象實現了控制項和資料來源之間的資料轉送;

  2、資料繫結的優勢:使用資料繫結要比編寫自己的代碼簡單得多;應該將它用於文本資料項目之外的範圍 —— 其他顯示內容也可以被綁定;對於 Windowos Forms 資料繫結能夠處理多個控制項同步的檢查相關資料來源;

  3、在對象不支援所需的屬性時,可以通過屏蔽當前的對象,然後添加一個想要的對象來支援資料繫結。

  三十九、使用.NET驗證

  1、ASP.NET中有五種控制項來驗證有效性,可以用CustomValidator派生一個新類來增加自己的認證器;

  2、Windows驗證需要子System.Windows.Forms.Control.Validating寫一個事件處理器。

  四十、根據需要選用恰當的集合

  1、數組有兩個比較明顯的缺陷:不能動態調整大小;調整大小非常耗時;

  2、ArrayList混合了一維數組和鏈表的特徵,Queue和Stack是建立在Array基礎上的特殊數組;

  3、當程式更加靈活的添加和刪除項時,可以使更加健壯的集合類型,當建立一個類比集合的類時,應當為其實現索引器和IEnumberable介面。

  四十一、DataSet優於自訂結構

  1、DataSet有兩個缺點個:使用XML序列化機制的DataSet與非.NET 代碼之間的互動不是很好;DataSet是一個非常通用的容器;

  2、強型別的DataSet打破了更多的設計規則,其獲得的開發效率要遠遠高於自己編寫的看上去更為優雅的設計。

  四十二、利用特性簡化反射

  通過設計和實現屬性類別,強制開發人員用他們來聲明可被動態使用的類型、方法和屬性,可以減少應用程式的執行階段錯誤,提高軟體的使用者滿意度。

  四十三、避免過度使用反射

  1、Invoke成員使用的參數和傳回值都是System.Object,在運行時進行類型的轉換,但出現問題的可能性也變得更多了;

  2、介面使我們可以得到一個更為清晰、也更具可維護性的系統,反射是一個很強大的晚期綁定機制,.NET架構使用它來實現Windows控制項和Web控制項的資料繫結。

  四十四、為應用程式建立特定的異常類

  1、需要不同的異常類的唯一原因是讓使用者在編寫catch處理器時能夠方便地對不同的錯誤採取不同的做法;

  2、可能有不同的修複行為時,我們才應該建立多種不同的異常類,通過提供異常基類所支援的所有構造器,可以為應用程式建立功能完整的異常類,使用InnerException屬性可以儲存更低層級錯誤條件所產生的所有錯誤資訊。

  四十五、優先選擇異常安全保證

  1、強異常保證在從異常中恢複和簡化異常處理之間提供了最好的平衡,在操作因為異常而中斷,程式的狀態保留不變;

  2、對將要修改的資料做防禦性的複製,對這些資料的防禦性複製進行修改,這中間的操作可能會引發異常,將臨時的副本和原對象進行交換;

  3、終結器、Dispose()方法和委派物件所綁定的目標方法在任何情況下都應當確保他們不會拋出異常。

  四十六、最小化互操作

  1、互操作有三個方面的代價:資料在託管堆和非託管堆之間的列舉成本,Managed 程式碼和Unmanaged 程式碼之間切換的成本,對開發人員來說與混合實境世界打交道的開發工作;

  2、在interop中使用blittable類型可以有效地在託管和非託管環境中來回複製,而不受對象內部結構的影響;

  3、使用In/Out特性來確保最貼切的不必要的多次複製,通過聲明資料如何被列舉來提高效能;

  4、使用COM Interop用最簡單的方式實現和COM組件的互操作,使用P/Invoke調用Win32 API,或者使用C++編譯器的/CLR開關來混合託管和非託管的代碼;

  四十七、優先選擇安全的程式碼

  1、儘可能的避免訪問非託管記憶體,隔離儲存不能防止來自Managed 程式碼和受信使用者的訪問;

  2、程式集在Web上運行時可以考慮使用隔離儲存,當某些演算法確實需要更高的安全許可時,應該將那些代碼隔離在一個單獨的程式集中。

  四十八、掌握相關工具與資源

  1、使用NUnit建立自動單元測試(整合在VS2010 中了);

  2、FXCop工具會擷取程式集中的IL代碼,並將其與異族編碼規則和最佳實務對照分析,最後報告違例情況;

  3、ILDasm是一個IL反組譯碼工具,可以協助我們洞察細節;

  4、Shared Source CLI是一個包含.NET架構核心和C#編譯器的實現源碼。

  四十九、為C#2.0做準備(這個規則現在已經沒什麼意義了,畢竟現在已經到了4.0 )  五十、瞭解ECMA標準 
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.