讀書筆記--《Effective C#》總結

值得推薦的一本書,適合初中級C#開發人員前端

第1章 C#語言元素

原則1:儘量的使用屬性(property),而不是數據成員(field)

  ● 屬性(property)一直是C#語言中比較有特色的存在。屬性容許將數據成員做爲共有接口的一部分暴露出去,同時仍舊提供面向對象環境下所需的封裝。屬性這個語言元素可讓你像訪問數據成員同樣使用,但其底層依舊是使用方法實現的。數據庫

  ● 使用屬性,能夠很是輕鬆的在get和set代碼段中加入檢查機制。編程

  須要注意,正由於屬性是用方法實現的,因此它擁有方法所擁有的一切語言特性:數組

  1)屬性增長多線程的支持是很是方便的。你能夠增強 get 和 set 訪問器(accessors)的實現來提供數據訪問的同步。安全

  2)屬性能夠被定義爲virtual。數據結構

  3)能夠把屬性擴展爲abstract。多線程

  4)可使用泛型版本的屬性類型。app

  5)屬性也能夠定義爲接口。框架

  6)由於實現實現訪問的方法get與set是獨立的兩個方法,在C# 2.0以後,你能夠給它們定義不一樣的訪問權限,來更好的控制類成員的可見性。ide

  7)而爲了和多維數組保持一致,咱們能夠建立多維索引器,在不一樣的維度上使用相同或不一樣類型。

 

  不管什麼時候,須要在類型的公有或保護接口中暴露數據,都應該使用屬性。若是能夠也應該使用索引器來暴露序列或字典。如今多投入一點時間使用屬性,換來的是從此維護時的更加遊刃有餘。

原則2:爲你的常量選擇readonly而不是const

  對於常量,C#裏有兩個不一樣的版本:運行時常量(readonly)和編譯時常量(const)。

  應該儘可能使用運行時常量,而不是編譯器常量。雖然編譯器常量略快,但並無運行時常量那麼靈活。應僅僅在那些性能異常敏感,且常量的值在各個版本之間絕對不會變化時,再使用編譯時常量。

  編譯時常量與運行時常量不一樣之處表如今於他們的訪問方式不一樣,由於Readonly值是運行時解析的:

  ● 編譯時常量(const)的值會被目標代碼中的值直接取代。

  ● 運行時常量(readonly)的值是在運行時進行求值。● 引用運行時生成的IL將引用到readonly變量,而不是變量的值。

  這個差異就帶來了以下規則:

  ● 編譯時常量(const)僅能用於數值和字符串。

  ● 運行時常量(readonly)能夠爲任意類型。運行時常量必須在構造函數或初始化器中初始化,由於在構造函數執行後不能再被修改。你可讓某個readonly值爲一個DataTime結構,而不能指定某個const爲  DataTIme。

  ● 能夠用readonly值保存實例常量,爲類的每一個實例存放不一樣的值。而編譯時常量就是靜態的常量。

  ● 有時候你須要讓某個值在編譯時才肯定,就最好是使用運行時常量(readonly)。

  ● 標記版本號的值就應該使用運行時常量,由於它的值會隨着每一個不一樣版本的發佈而改變。

  ● const優於readonly的地方僅僅是性能,使用已知的常量值要比訪問readonly值略高一點,不過這其中的效率提高,能夠說是微乎其微的。

 

  綜上,在編譯器必須獲得肯定數值時,必定要使用const。例如特性(attribute)的參數和枚舉的定義,還有那些在各個版本發佈之間不會變化的值。除此以外的全部狀況,都應儘可能選擇更加靈活的readonly常量。

原則3:選擇is或者as操做符而不是作強制類型轉換(翻譯)

  ● C#中,is和as操做符的用法歸納以下:

  is : 檢查一個對象是否兼容於其餘指定的類型,並返回一個Bool值,永遠不會拋出異常。

  as:做用與強制類型轉換是同樣,可是永遠不會拋出異常,即若是轉換不成功,會返回null。

 

  ● 儘量的使用as操做符,由於相對於強制類型轉換來講,as更加安全,也更加高效。

  ● as在轉換失敗時會返回null,在轉換對象是null時也會返回null,因此使用as進行轉換時,只需檢查返回的引用是否爲null便可。

  ● as和is操做符都不會執行任何用戶自定義的轉換,它們僅當運行時類型符合目標類型時才能轉換成功,也不會在轉換時建立新的對象。

  ● as運算符對值類型是無效,此時可使用is,配合強制類型轉換進行轉換。

  ● 僅當不能使用as進行轉換時,才應該使用is操做符。不然is就是多餘的。

原則4:用條件屬性而不是#if預編譯塊

  ● 因爲#if/#endif很容易被濫用,使得編寫的代碼難於理解且更難於調試。C#爲此提供了一條件特性(Conditional attribute)。使用條件特性能夠將函數拆分出來,讓其只有在定義了某些環境變量或設置了某個值以後才能編譯併成爲類的一部分。Conditional特性最經常使用的地方就是將一段代碼變成調試語句。 

  ● Conditional特性只可應用在整個方法上,另外,任何一個使用Conditional特性的方法都只能返回void類型。不能再方法內的代碼塊上應用Conditional特性。也不能夠在有返回值的方法上應用Conditional特性。但應用了Conditional特性的方法能夠接受任意數目的引用類型參數。 

  ● 使用Conditional特性生成的IL要比使用#if/#Eendif時更有效率。同時,將其限制在函數層面上能夠更加清晰地將條件性的代碼分離出來,以便進一步保證代碼的良好結構。

原則5:始終提供ToString()

  1. 人最容易理解的是字符串,而Object.ToString的默認行爲是返回類型名,正確的實現ToString有利於調試和UI等。

  2. Console.WriteLine和String.Format等都支持IFormattable接口,注意IFormattable.ToString和Object.ToString的兼容。

原則6:區別值類型數據和引用類型數據

  ● C#中能夠建立兩種類型:值類型和引用類型。若是兩個引用類型的變量指向的是同一個對象,它們將被認爲是「引用相等」。若是兩個值類型的變量類型相同,並且包含一樣的內容,它們被認爲是「值相等」。這也是等同性判斷須要如此多方法的緣由。

  ● 當咱們建立本身的類型時(不管是類仍是struct),應爲類型定義「等同性」的含義。C#提供了4種不一樣的函數來判斷兩個對象是否「相等」。

  1)public static bool ReferenceEquals (object left, object right);判斷兩個不一樣變量的對象標識(object identity)是否相等。不管比較的是引用類型仍是值類型,該方法判斷的依據都是對象標識,而不是對象內容。

  2)public static bool Equals (object left, object right); 用於判斷兩個變量的運行時類型是否相等。

  3)public virtual bool Equals(object right); 用於重載

  4)public static bool operator ==(MyClass left, MyClass right); 用於重載

  ● 不該該覆寫Object.referenceEquals()靜態方法和Object.Equals()靜態方法,由於它們已經完美的完成了所須要完成的工做,提供了正確的判斷,而且該判斷與運行時的具體類型無關。對於值類型,咱們應該老是覆寫Object.Equals()實例方法和operatior==( ),以便爲其提供效率更高的等同性判斷。對於引用類型,僅當你認爲相等的含義並不是是對象標識相等時,才須要覆寫Object.Equals( )實例方法。在覆寫Equals( )時也要實現IEquatable<T>。

原則7:選擇恆定的原子值類型數據

  常量性的類型使得咱們的代碼更加易於維護。不要盲目地爲類型中的每個屬性都建立get和set訪問器。對於那些目的是存儲數據的類型,應該儘量地保證其常量性和原子性。

原則8:確保0對於值類型數據是有效的

  在建立自定義枚舉值時,請確保0是一個有效的選項。若你定義的是標誌(flag),那麼能夠將0定義爲沒有選中任何狀態的標誌(好比None)。即做爲標記使用的枚舉值(即添加了Flags特性)應該老是將None設置爲0。

原則9:明白幾個相等運算之間的關係

  1. 對於ValueType:(對應struct)

   public override bool Equals(object obj);

  它的實現主要是經過反射來對比各個字段,所以這個默認實現效率很低。ValueType的默認實現中,並不能直接將兩個二進制塊進行memcmp,由於形如struct A{ string s; }這樣的結構,二進制層次上的對比是沒有意義的。事實上,C#編譯器也沒有提供自動生成T.Equals的服務(即對於用戶沒有提供Equals實現的struct,編譯器何不自動生成逐字段對比的C#代碼?),緣由不明。

  因此,若是特定struct性能攸關,應該手工實現Equals進行逐字段比較以得到更佳性能。另外考慮實現語法糖operator==來調用Equals。

  2. 對於Object: (對應class)

  public static bool ReferenceEquals(object objA, object objB);

  public static bool Equals(object objA, object objB);

   public virtual bool Equals(object obj);

  public static bool operator == (object objA, object objB);

  Object基類中的默認實現全是引用比較,即用於判斷是不是同一對象。其中ReferenceEquals提供最底層實現,operator ==調用ReferenceEquals, static Equals進行對象非空驗證而後調用virtual Equals, 而virtual Equals默認也是調用ReferenceEquals。

  若是須要給引用類型提供其餘比較語義,如string,則實現virtual Equals,而後重載operator ==調用virtual Equals。

原則10:明白GetHashCode()的缺陷

  ● GetHashCode( )方法在使用時會有很多坑,要謹慎使用。GetHashCode()函數僅會在一個地方用到,即爲基於散列(hash)的集合定義鍵的散列值時,此類集合包括HashSet<T>和Dictionary<K,V>容器等。對引用類型來說,索然能夠正常工做,可是效率很低。對值類型來說,基類中的實現有時甚至不正確。並且,編寫的本身GetHashCode( )也不可能既有效率又正確。

  ● 在.NET中,每一個對象都有一個散列碼,其值由System.Object.GetHashCode()決定。

  ● 實現本身的GetHashCode( )時,要遵循上述三條原則:

  1)若是兩個對象相等(由operation==定義),那麼他們必須生成相同的散列碼。不然,這樣的散列碼將沒法用來查找容器中的對象。

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

  3)對於全部的輸入,散列函數應該在全部整數中按隨機分別生成散列碼。這樣散列容器才能獲得足夠的效率提高。

原則11:選擇foreach循環

  1. foreach會自動針對不一樣的容器,生成不一樣的il碼以優化效率。例如對數組,foreach不會經過IEnumerable遍歷,而是直接使用下標。

  2. foreach能夠正確遍歷起始下標非0的數組和多維數組。下標非0數組是經過Array.CreateInstance建立的。

  3. foreach遍歷數組,由於能夠保證訪問數組的每一個元素的時候不越界,故foreach對應的下標訪問實現不會有下標越界檢查的開銷。在我使用的C#3.5中測試,foreach並無加速效果,恐怕由於在高版本中,下標越界檢查已經移到了clr的實現中(il的ldelem),故foreach並不比for循環快。

第2章 .NET資源管理

原則12:選擇變量初始化而不是賦值語句

  成員初始化器是保證類型中成員均被初始化的最簡單的方法——不管調用的是哪個構造函數。初始化器將在全部構造函數執行以前執行。使用這種語法也就保證了你不會再添加的新的構造函數時遺漏掉重要的初始化代碼。

  綜上,如果全部的構造函數都要將某個成員變量初始化成同一個值,那麼應該使用初始化器。

原則13:用靜態構造函數初始化類的靜態成員

  ● C#提供了有靜態初始化器和靜態構造函數來專門用於靜態成員變量的初始化。

  ● 靜態構造函數是一個特殊的函數,將在其餘全部方法執行以前以及變量或屬性被第一次訪問以前執行。能夠用這個函數來初始化靜態變量,實現單例模式或執行類可用以前必須進行的任何操做。

  ● 和實例初始化同樣,也可使用初始化器語法來替代靜態的構造函數。若只是須要爲某個靜態成員分配空間,那麼不妨使用初始化器的語法。而如果要更復雜一些的邏輯來初始化靜態成員變量,那麼可使用靜態構造函數。

  ● 使用靜態構造函數而不是靜態初始化器最多見的理由就是處理異常。在使用靜態初始化器時,咱們沒法本身捕獲異常。而在靜態構造函數中卻能夠作到。

原則14:使用構造函數鏈

  ● 編寫構造函數不少時候是個重複性的勞動,若是你發現多個構造函數包含相同的邏輯,能夠將這個邏輯提取到一個通用的構造函數中。這樣既能夠避免代碼重複,也能夠利用構造函數初始化器來生成更高效的目標代碼。

  ● C#編譯器將把構造函數初始化器看作是一種特殊的語法,並移除掉重複的變量初始化器以及重複的基類構造函數調用。這樣使得最終的對象能夠執行最少的代碼來保證初始化的正確性。

  ● 構造函數初始化器容許一個構造函數去調用另外一個構造函數。而C# 4.0添加了對默認參數的支持,這個功能也能夠用來減小構造函數中的重複代碼。你能夠將某個類的全部構造函數統一成一個,併爲全部的可選參數指定默認值。其餘的幾個構造函數調用某個構造函數,並提供不一樣的參數便可。

原則15:使用using和try/finally來作資源清理

  對於文件等有Close方法的IDisposable對象,應該使用Dispose方法來代替Close,由於前者還會進行GC.SuppressFinalize操做,明顯提升性能。

原則16:垃圾最小化

  1. 頻繁調用的成員方法中若是有局部做用域的資源,嘗試把資源做爲對象的成員數據。如在OnPaint中使用的Font做爲成員的話就沒必要每次都建立。

  2. 經常使用的資源考慮做爲靜態對象,還能夠做爲屬性在get中進行延遲加載等。如Brush.Black等。

  3. 常量性數據避免頻繁修改。如string,可使用string.format和StringBuilder來減小垃圾。

原則17:裝箱和拆箱的最小化

  注意將struct轉換爲引用類型,都會形成裝箱。如將struct轉換爲object/ValueType/interface。

原則18:實現標準的處理(Dispose)模式

  ● GC能夠高效地管理應用程序使用的內存。不過建立和銷燬堆上的對象仍舊須要時間。如果在某個方法中建立了太多的引用對象,將會對程序的性能產生嚴重的影響。

 

  這裏有一些規則,能夠幫你儘可能下降GC的工做量:

  1)若某個引用類型(值類型無所謂)的局部變量用於被頻繁調用的例程中,那麼應該將其提高爲成員變量。

  2)爲經常使用的類型實例提供靜態對象。

  3)建立不可變類型的最終值。好比string類的+=操做符會建立一個新的字符串對象並返回,屢次使用會產生大量垃圾,不推薦使用。對於簡單的字符串操做,推薦使用string.Format。對於複雜的字符串操做,推薦使用StringBuilder類。

第3章 使用C#表達設計

原則19:選擇定義和實現接口而不是繼承

  1. 接口表示「behaves like」,而繼承表示「is a」。繼承同一個基類的多個類型是相關類型,而繼承同一個接口的多個類型能夠徹底無關,只是都包含一組行爲。

  2. 接口的簽名相對較穩定,由於對接口的修改將影響因此實現該接口的類型;而修改繼承體系中的基類,若是有默認實現的話,派生類不必定須要調整。

  3. 公開接口相比公開具體類,前者暴露更少的實現細節。

原則20:明辨接口實現和虛函數重載的區別

  實現接口時,接口方法的具體修飾如virtual、abstract等能夠自由設置。

原則21:用委託來表示回調

  在C#中,回調是用委託來實現的,主要要點以下:

  1)委託爲咱們提供了類型安全的回調定義。雖然大多數常見的委託應用都和事件有關,但這並非C#委託應用的所有場合。當類之間有通訊的須要,而且咱們指望一種比接口所提供的更爲鬆散的耦合機制時,委託即是最佳的選擇。

  2)委託容許咱們在運行時配置目標並通知多個客戶對象。委託對象中包含一個方法的應用,該方法能夠是靜態方法,也能夠是實例方法。也就是說,使用委託,咱們能夠和一個或多個在運行時聯繫起來的客戶對象進行通訊。 

  3)因爲回調和委託在C#中很是經常使用,以致於C#特意以lambda表達式的形式爲其提供了精簡語法。

  4)因爲一些歷史緣由,.NET中的委託都是多播委託(multicast delegate)。多播委託調用過程當中,每一個目標會被依次調用。委託對象自己不會捕捉任何異常。所以,任何目標拋出的異常都會結束委託鏈的調用。

原則22:用事件定義對外接口

  ● 事件提供了一種標準的機制來通知監聽者,而C#中的事件其實就是觀察者模式的一個語法上的快捷實現。

  ● 事件是一種內建的委託,用來爲事件處理函數提供類型安全的方法簽名。任意數量的客戶對象均可以將本身的處理函數註冊到事件上,而後處理這些事件,這些客戶對象無需在編譯器就給出,事件也沒必要非要有訂閱者才能正常工做。

  ● 在C#中使用事件能夠下降發送者和可能的通知接受者之間的耦合,發送者能夠徹底獨立於接受者進行開發。

原則23:避免返回內部類對象的引用

  ● 若將引用類型經過公有接口暴露給外界,那麼對象的使用者便可繞過咱們定義的方法和屬性來更改對象的內部結構,這會致使常見的錯誤。

  ● 共有四種不一樣的策略能夠防止類型內部的數據結構遭到有意或無心的修改:

  1)值類型。當客戶代碼經過屬性來訪問值類型成員時,實際返回的是值類型的對象副本。

  2)常量類型。如System.String。

  3)定義接口。將客戶對內部數據成員的訪問限制在一部分功能中。

  4)包裝器(wrapper)。提供一個包裝器,僅暴露該包裝器,從而限制對其中對象的訪問。

原則24:選擇申明式編程而不是命令式編程

  主要指特性的應用(System.Attribute的派生類)。例如序列化特性等

原則25:讓你的類型支持序列化

   任何可序列化的類型要求其主要數據成員也應該可序列化,因此考慮是否要讓類型支持序列化的時候,還須要考慮未來該類型是否有可能被用於其餘可序列化類型做爲其成員(即放棄A的序列化能力,會給包含A的可序列化類型B帶來麻煩)。通常只有UI對象等不須要序列化能力,因此大部分類型都應該儘量的支持序列化。

原則26:用IComparable和IComparer實現對象的順序關係

   排序過程當中的比較操做頻率很高,須要儘量高效,注意減小沒必要要的裝箱和使用IComparer代替委託。

原則27:避免使用ICloneable

  1. 值類型不支持多態,且自己的賦值操做符效率很高,通常不須要實現ICloneable。

  2. 引用類型實現ICloneable的時候,考慮像C++那樣,先實現拷貝構造函數,而後用拷貝構造函數實現Clone。

原則28:避免轉換操做

  建議使用單參數構造函數代替類型轉換。首先,隱式類型轉換因爲過於隱蔽容易形成bug須要嚴格控制,如C++中慎用operator T和要求單參構造函數聲明爲explicit,都是爲了限制隱式類型轉換,規則應用到C#後,還剩下兩種選擇,即單參構造函數和explicit的類型轉換,前者正是本條款提倡的,然後者,只有當轉換後的類型具備常量性的時候可使用(若是轉換爲能夠修改類型,由於返回的對象是臨時對象,應用在這個臨時對象的修改會無效,忽略了這點可能會產生較隱蔽的bug。如Array.Sort((int[])myListType);)。

原則29:僅在對基類進行強制更新時才使用new修飾符

  ● 使用new操做符修飾類成員能夠從新定義繼承自基類的非虛成員。

  ● new修飾符只是用來解決升級基類所形成的基類方法和派生類方法衝突的問題。

  ● new操做符必須當心使用。若爲所欲爲的濫用,會形成對象調用方法的二義性。

第4章 建立二進制組件

原則30:選擇與CLS兼容的程序集

   要讓程序集可以被不一樣.Net語言訪問(語言互操做性),程序集須要與CLS兼容。使用特性[assembly: CLSCompliant(true)],讓編譯器檢查CLS兼容性。CLS兼容意味着,公開或保護的方法和接口與CLS兼容。

原則31:選擇小而簡單的函數

  較小的函數比大函數有更少的局部變量,有利於JIT合理分配寄存器,有利於內聯

  將C#代碼翻譯成可執行的機器碼須要兩個步驟。

  C#編譯器將生成IL,並放在程序集中。隨後,JIT將根據須要逐一爲方法(或是一組方法,若是涉及內聯)生成機器碼。短小的方法讓JIT編譯器可以更好地平攤編譯的代價。短小的方法也更適合內聯。

  除了短小以外,簡化控制流程也很重要。控制分支越少,JIT編譯器也會越容易地找到最適合放在寄存器中的變量。

  因此,短小方法的優點,並不只體如今代碼的可讀性上,還關係到程序運行時的效率。

原則32:選擇小而內聚的程序集

  程序集的劃分標準之一:程序集的功能應該可以一句話歸納。

原則33:限制類型的訪問

  可使用內部類實現公開接口等

原則34:建立大容量的Web API

  大粒度的Web API、RPC API、腳本API等,因爲載荷大,調用頻率更低,相比小粒度的API具備跨邊界通訊總成本小的優勢

第5章 使用框架

原則35:選擇重寫函數而不是使用事件句柄

  面對override和event兩種事件處理選擇的時候,前者更優:

  (1)覆蓋虛方法性能更高,還可應控制調用基類方法觸發event的時機。

  (2)event中的方法鏈是動態表,有可能因未知的緣由致使方法沒有被調用。如方法鏈的前端有異常拋出或委託對象被清空等。

原則36:利用.Net運行時診斷

  1. 在編譯時,能夠經過編譯選項控制System.Diagnostics.Trace和System.Diagnostics.Debug的開關。

  2. 在運行時,能夠經過配置文件配置Trace的輸出目標文件和等級等。

原則37:使用標準的配置機制

  除.Net默認的配置文件外,還能夠利用Xml序列化實現簡單的讀寫配置

原則38:使用和支持數據綁定

  應該儘可能利用UI庫提供的數據綁定功能,它可以大幅簡化代碼邏輯。數據綁定容許配置數據源和目標屬性、容許控制源和目標類型不匹配時的轉換方式,數據綁定可以正確處理數據同步的時機,避免了在多處編寫重複的同步代碼。

原則39:使用.Net驗證

原則40:根據需求選擇集合

原則41:選擇DataSet而不是自定義的數據結構

  DataSet因爲有數據庫的視圖、約束、事務等邏輯,很容易和UI結合。缺點是DataSet中表項是弱類型。

原則42:使用特性進行簡單的反

   特性的一種用法:給類型或成員打上指定特性做爲標記,用於在反射時進行類型、方法的篩選。

原則43:請勿濫用反射

   反射是晚綁定,容易引入人爲bug,除非對動態編碼有高要求,不然儘可能優先考慮用工廠模式、接口、委託等方案替代反射

原則44:建立應用程序特定的異常類

  1. 選擇拋出異常是由於clr拋出的異常信息有限,以及有的錯誤狀況如不及時反饋會在後期爆發時無從追查。

  2. 外部會根據錯誤緣由作區別處理時,才考慮使用特定類型的異常。

  3. 使用新異常類型來表達特殊錯誤,相比始終拋出System.Exception並用描述字符串區分錯誤緣由的方案,後者由於依賴於字符串無強類型保證,不利於重構且易引發bug。

第6章 雜項討論

原則45:選擇強異常來保護程序

  1. 基本保證:拋出異常後,無資源泄漏且對象都處在有效狀態。垃圾收集和using避免了資源泄漏,因此只須要注意不要因異常打亂執行流程而致使對象狀態破壞。

  2. 強保證:拋出異常致使操做中斷後,對象狀態應該和操做前相同。C++實踐:拷貝對象->修改拷貝後對象->交換拷貝和源對象。

  3. 無拋保證:不拋出異常。C#中至少有3組方法不該該拋出異常:

  (1)終結器(析構函數)。終結器被垃圾回收線程調用,拋出異常將直接致使程序結束。C++也禁止析構函數拋出異常,理由是構成雙異常的狀況下致使程序崩潰。

  (2)Dispose方法。該方法通常嵌套在finally語句塊中,若是finally語句塊由於有其餘異常拋出才被動執行,那語句塊中的Dispose再拋出異常將致使前一個異常被覆蓋(C#面對雙異常,採起後者覆蓋前者的策略),結果最初的異常信息丟失。

  (3)委託方法。委託默認是多播委託,若是方法鏈中的一個方法拋出異常,後面的方法將不被調用。

原則46:最小化與其它非託管代碼的交互

  1. interop在數據傳輸方面存在marshal開銷。使用blittable類型(基礎類型、基礎類型數組、基礎類型的struct包裝)能夠直接傳輸避免marshal。聲明In、Out特性和選擇最合適的聲明也有利於提升效率。

  2. interop在託管和非託管代碼間切換的開銷。存在三種選擇:

  (1)Com Interop。由於屬性頻繁使用形成交互頻繁,效率低。適合和Com交互。

  (2)Platform Invoke。效率高,但須要聲明每一個函數,且無天然的面向對象語法。適合和C API交互。

  (3)C++/CLI。易於將C++的類型包裝成託管類型。適合和C++交互。

  3. interop複雜的語法增長了開發成本。

原則47:選擇安全的代碼

  1. unsafe代碼塊最好集中到單獨的程序集。(爲什麼?若是要求集中到單獨的AppDomain我明白。)

  2. 爲部分受信程序集提供隔離存儲區。如Web上的代碼。

原則48:瞭解更多的工具和資源

  單元測試(NUnit)、代碼分析(FxCop)、IL反彙編(ILDasm)、官方網站和社區、.Net和C#源碼(rotor)等。

原則49:爲C#2.0作好準備

原則50:瞭解ECMA標準

相關文章
相關標籤/搜索