《深入理解 C# (第2版)》 - 學習筆記

**《深入理解 C#》 (第2版)

========== ========== ==========
[作者] (英) Jon Skeet
[譯者] (中) 周靖 朱永光 姚琪琳
[出版] 人民郵電出版社
[版次] 2012年01月 第1版
[印次] 2012年01月 第1次 印刷
[定價] 79.00元
========== ========== ==========

【關於本書】

具體地說, C# 作爲一種語言,它的基礎是各種各樣的 “框架庫” (.NET Framework 中的各種庫) 以及一個強大的運行時 (runtime) 。藉助它們,我們可以將抽象的東西轉變成現實。

【第01章】

(P013)

LINQ (Language Integrated Query , 語言集成查詢) ,是 C# 3 的核心之所在。顧名思義。 LINQ 是關於查詢的,其目的是使用一致的語法和特性,以一種易閱讀、可組合的方式,使對多數據源的查詢變得簡單。

(P014)

查詢表達式唯一的好處就是 where 子句顯得更簡單。

【第02章】

(P023)

實際上,委託在某種程度上提供了間接的方法。換言之,不需要直接指定一個行爲,而是將這個行爲用某種方式 “包含” 在一個對象中。

可以選擇將委託類型看做只定義了一個方法的接口,將委託的實例看做實現了那個接口的一個對象。

(P024)

爲了讓委託做某事,必須滿足4個條件 :

  1. 聲明委託類型;

  2. 必須有一個方法包含了要執行的代碼;

  3. 必須創建一個委託實例;

  4. 必須調用 (invoke) 委託實例;

(P026)

如果有一個委託類型的變量,就可以把它視爲方法本身。

(P028)

委託實例實際有一個操作列表與之關聯,這稱爲委託實例的調用列表 (invocation list) 。

System.Delegate 類型的靜態方法 Combine 和 Remove 負責創建新的委託實例。其中, Combine 負責將兩個委託實例的調用列表連接到一起,而 Remove 負責從一個委託實例中刪除另一個的調用列表。

委託是不易變的,創建了一個委託實例後,有關它的一切就不能改變。這樣一來,就可以安全地傳遞委託實例,並把它們與其他委託實例合併,同時不必擔心一致性、線程安全性或者是否有其他人試圖更改它的操作。

(P029)

事件不是委託類型的字段。

對於事件來說,必須是一個委託類型。

(P030)

對於一個純粹的事件,你所能做的事情就是訂閱 (添加一個事件處理程序) 或者取消訂閱 (刪除一個事件處理程序) 。

類內的代碼能看見字段;類外的代碼只能看見事件。

(P037)

數組類型是引用類型,即使元素類型是值類型。

枚舉是值類型。

委託類型是引用類型。

接口類型是引用類型,但可由值類型實現。

(P039)

變量的值是在它聲明的位置存儲的。

只有局部變量 (方法內部聲明的變量) 和方法參數在棧上。

(P040)

當你調用類型變量值的 GetType() 方法時總是伴隨着裝箱過程,因爲它不能被重載。

(P041)

引用類型作爲方法參數使用時,參數默認是以 “值傳遞” 方式來傳遞的 —— 但值本身是一個引用。

【第03章】

(P047)

所謂 “函數化” 的編程風格,是指鼓勵開發者更多地利用委託。

(P048)

從根本上說,泛型實現了類型和方法的 “參數化” ,就像在普通的方法調用中,經常要用參數來告訴它們使用什麼值。

(P052)

類型參數是真實類型的佔位符。

在泛型聲明中,類型參數要放在一對尖括號內,並以逗號分隔。

使用泛型類型或方法時,要用真實的類型代替,這些真實的類型稱爲類型實參 (type argument) 。

如果沒有爲任何類型參數提供類型實參,聲明的就是一個未綁定泛型類型 (unbound generic type) 。如果指定了類型實參,該類型就稱爲一個已構造類型 (constructed type) 。

我們知道,類型 (無論是否是泛型) 可以看做是對象的藍圖。同樣,未綁定泛型類型是已構造類型的藍圖。

在 C# 代碼中,唯一能看見未綁定泛型類型的地方 (除了作爲聲明之外) 就是在 typeof 操作符內。

類型參數 “接收” 信息,類型實參 “提供” 信息,這個思路與 方法參數 / 方法實參 是一樣的。只不過類型實參必須爲類型,而不能爲任意的值。只有在編譯時才能知道類型實參的類型,它可以是 (或包含) 相關上下文中的類型參數。

(P054)

泛型類型可以重載,只需改變一下類型參數的數量就可以了。

(P057)

將 API 的一部分變成泛型後,以前強類型的方法調用就需要進行強制類型轉換。

(P062)

調用泛型方法時,指定類型實參常常會顯得很多餘。

類型推斷只適用於泛型方法,不適用於泛型類型。

(P063)

在 C# 語言規範中,只提供了數量有限的推斷步驟。

雖然很少需要用到默認值,但它偶爾還是有用的。

(P064)

輸出參數也稱爲 out 參數,如果希望由方法本身初始化參數,允許向方法傳遞一個未初始化的實參,那麼在聲明參數時,就要附加 out 關鍵字作爲前綴。

(P066)

共有 4 個主要的泛型接口可用於比較。 IComparer<T> 和 IComparable<T> 用於排序 (判斷某個值是小於、等於還是大於另一個值) ,而 IEqualityComparer<T> 和 IEquatable<T> 通過某種標準來比較兩個項的相等性,或查找某個項的散列 (通過與相等性概念匹配的方式) 。

如果換一種方式來劃分這 4 個接口, IComparer<T> 和 IEqualityComparer<T> 用於那些能夠比較兩個不同值的類型,而 IComparable<T> 和 IEquatable<T> 的實例則用於它們本身和其他值之間的比較。

(P073)

一個基本的原則是,如果沒有問題,泛型接口都應該繼承對應的非泛型接口,這樣可以實現協變性。

(P074)

實現接口所規定的的方法或屬性時,附加接口名作爲前綴,即稱爲 “顯式接口實現” 。

(P075)

反射的一切都是圍繞 “檢查對象及其類型” 展開的。

(P078)

泛型不支持協變性 —— 它們是不變體。

【第04章】

(P091)

Nullable<T> 最重要的部分就是它的屬性,即 HasValue 和 Value 。

(P092)

Nullable<T> 引入了一個名爲 GetValueOrDefault 的新方法,它有兩個重載方法,兩者均在存在一個實例的前提下返回該實例的值,否則返回一個默認值。其中一個重載方法沒有任何參數 (在這種情況下會使用基礎類型的泛型默認值) ,另一個重載方法則允許你指定要返回的默認值。

【第05章】

(P114)

C# 2 支持從方法組到一個兼容委託類型的隱式轉換。

(P117)

根據約定,事件處理方法應具有包含兩個參數的簽名。第 1 個參數是 object 類型,代表事件的來源;第 2 個參數則負責攜帶與事件有關的任何額外信息,該參數是從 EventArgs 派生的一個類型。

返回類型協變性和參數類型逆變性可以同時使用,雖然這樣做幾乎沒有任何實際的用處。

(P119)

.NET 2.0 引入了一個泛型委託類型 Action<T> ,我們將在例子中使用委託。它的簽名非常簡單 (除了它是泛型這一事實以外) : public delegate void Action<T>(T obj) 。

(P120)

匿名方法的語法 : 先是 delegate 關鍵字,再是參數 (如果有的話) ,隨後是一個代碼塊,其中包含了對委託實例的操作進行定義的代碼。

基本上,在普通方法主體中能做的事情,在匿名方法中都能做。同樣,匿名方法的結果是一個委託實例,可以像使用其他委託實例那樣使用它。

逆變性不適用於匿名方法,必須指定和委託類型完全匹配的參數類型。

(P121)

Action<T> 委託的返回類型是 void ,所以不必從匿名方法返回任何東西。

.NET 2.0 中的 Predicate<T> 委託類型,下面列出了它的簽名 : public delegate bool Predicate<T>(T obj) 。

(P122)

謂語通常在需要篩選和匹配操作中使用。

Predicate<T> 類型聲明的返回類型恰好是 bool 。

(P124)

匿名方法是 C# 2 以被捕捉的變量的形式來實現,在別的地方成爲閉包的一個特性。

(P125)

匿名方法能使用在聲明該匿名方法的方法內部定義的局部變量。

(P127)

簡單地說,捕獲變量能簡化編程,避免專門創建一些類來存儲一個委託需要處理的信息 (作爲參數傳遞的信息除外) 。

FindAll 的參數是一個 Predicate<T> 委託。

【第06章】

(P138)

如果方法聲明的返回類型是非泛型接口,那麼迭代器塊的生成類型 (yield type) 是 object ,否則就是泛型接口的類型參數。

在迭代器中不允許包含普通的 return 語句 —— 只能是 yield return 。

(P141)

迭代器代碼塊不能實現具有 ref 或 out 參數的方法。

(P143)

只要調用者使用了 foreach 循環,迭代器塊中的 finally 將按照你期望的方式工作。

(P147)

迭代器方法中的 using 語句扮演了 try / finally 塊的角色。

(P148)

LINQ 的核心特性之一,是使用 Where 方法進行篩選。

【第07章】

(P154)

創建分部類型是非常容易做的事情 —— 你只需在涉及的每個文件的類型的聲明部分附加一個上下文關鍵字 partial 。

(P158)

分部方法的聲明方式與抽象方法相同 : 只使用 partial 修飾符提供簽名而無須任何實現。同樣,實際的實現還需要 partial 修飾符,不然就和普通方法一樣了。

由於方法可能不存在,分部方法必須具有 void 返回類型,不能獲取 out 參數。它們必須是私有的,不過可以是靜態的 並且 / 或是 泛型的。如果方法沒有在任何文件中實現,那麼整個調用語句就會被移除,包括任何參數的計算語句。

(P159)

實際上如果不存在可見的構造函數 (包括受保護的) ,那麼類實際上也就是密封的了。

(P160)

如果你不爲類提供任何構造函數,那麼 C# 1 編譯器總是會提供一個公有的默認的無參數構造函數。

我們不希望出現任何可見的構造函數,所以不得不提供一個私有的。

C# 2 編譯器知道靜態類不用包含任何構造函數,所以它也不會提供默認的。實際上,編譯器在類定義上執行了大量的約束 :

  1. 類不能聲明爲 abstract 或 sealed ,雖然兩者都是隱含聲明的;

  2. 類不能設定任何要實現的接口;

  3. 類不能設定基類型;

  4. 類不能包含任何非靜態成員,包括構造函數;

  5. 類不能包含任何操作符;

  6. 類不能包含任何 protected 或 protected internal 成員;

應當注意,即使所有成員都必須爲靜態的,你還是要把它們都顯式地聲明爲靜態的,除了嵌套類型和常量。雖然嵌套類型是外圍類的隱式靜態成員,不過如果不要求的話,嵌套類型本身可以不用是靜態的。

(P161)

讓類成爲靜態的,就是在說你絕對不會創建該類的任何實例。

在 C# 1 中取值方法和賦值方法必須具有相同的可訪問性 —— 它作爲屬性聲明的一部分進行聲明,而不是作爲取值方法或賦值方法聲明的一部分進行聲明的。

(P162)

在 C# 的其他地方,在給定的情況下,默認的訪問修飾符可能大部分都是私有的。換句話說。如果某些內容能被聲明爲私有,那麼省略的訪問修飾符就被完全默認爲私有。這是一種很好的語言設計元素,因爲這樣很難意外地發生錯誤 : 如果你希望某些內容更加公開,在你使用它的時候會注意到。

如果你不設定任何東西,那麼默認情況下 取值方法 / 賦值方法 和屬性本身整體上保持一致的訪問修飾符。

還要注意,你不能把屬性本身聲明爲私有,而讓取值方法是公有的 —— 你只能設置比屬性更私有的特殊 取值方法 / 賦值方法 。

C# 1 的 using 指令能夠用於兩種情況 —— 一種是爲命名空間和類型創建一個別名,另外一種就是將一個命名空間引入到當編譯器查找某個類型時可以搜索到的上下文列表中。

在 C# 2 中,有 3 種別名種類 : C# 1 的命名空間別名、全局命名空間別名和外部別名。

(P166)

對 pragma 指令進行描述通常都非常簡單 : pragma 指令就是一個由 #pragma 開頭的代碼行所表示的預處理指令,它後面能包含任何文本。

【第08章】

(P178)

不能在所有情況下爲所有變量都使用隱式類型。只有在以下情況下才能用它 :

  1. 被聲明的變量是一個局部變量,而不是靜態字段和實例字段;

  2. 變量在聲明的同時被初始化;

  3. 初始化表達式不是一個方法組,也不是一個匿名函數 (不進行強制類型轉換) ;

  4. 初始化表達式不是 null ;

  5. 語句中只聲明瞭一個變量;

  6. 你希望變量擁有的類型是初始化表達式的編譯時類型;

  7. 初始化表達式不包含正在聲明的變量;

(P184)

集合初始化列表並非只能應用於列表。任何實現了 IEnumerable 的類型,只要它爲初始化列表中出現的每個元素都提供了一個恰當的公有的 Add 方法,就可以使用這個特性。

(P192)

如果你要創建的一個類型只在一個方法中使用,而且其中只包含了字段和普通屬性,就考慮一下能否使用匿名類型。

(P193)

匿名類型允許你只保留特定情況下需要的數據,這些數據採取的是適用於那種情況的形式,不必每次都單調重複地寫一個新的類型。

隱式類型的數組和匿名類型只有在與其他 C# 3 特性配合的時候纔會體現它們的價值。

【第09章】

(P194)

LINQ 的基本功能就是創建操作管道,以及這些操作需要的任何狀態。這些操作表示了各種關於數據的邏輯 : 如何篩選、如何排序以及如何將不同的數據源聯接到一起,等等。當 LINQ 查詢在 “進程內” 執行時,那些操作通常用委託來表示。

LINQ to Objects 處理的是同一個進程中的數據序列。相比之下,像 LINQ to SQL 這樣的 provider 將工作交給 “進程外” 的系統 (比如數據庫) 去處理。

(P195)

執行委託只是 LINQ 的衆多能力之一。

從許多方面, Lambda 表達式都可以看做是 C# 2 的匿名方法的一種演變。

匿名方法能做的幾乎一切事情都可以用 Lambda 表達式來完成。

匿名方法可以簡明地忽略參數,但 Lambda 表達式不具備的這一特性。

在 .NET 3.5 的 System 命名空間中,有 5 個泛型 Func 委託類型。 Func 並無特別之處 —— 只是它提供了一些好用的預定義泛型類型,在很多情況下能幫助我們處理問題。每個委託簽名都獲取 0 ~ 4 個參數,參數類型是用類型參數來指定的。最後一個類型參數用作每種情況下的返回類型。

(P196)

當你想使用 void 爲返回類型時,可使用 Action<...> 系列的委託,其功能相同。

Action 的單參數的版本在 .NET 2.0 中就有了,但其他都是 .NET 3.5 新增的。

如果 4 個參數還嫌不夠, .NET 4 將 Action<...> 和 Func<...> 家族擴展爲擁有 16 個參數,因此 Func<T1, ..., T16, TResult> 擁有讓人欲哭無淚的 17 個類型參數。

Lambda 表達式最冗長的形式是 : { 顯式類型參數列表} => { 語句 } 。

=> 部分是 C# 3 新增的,它告訴編譯器我們正使用一個 Lambda 表達式。

(P197)

在閱讀 Lambda 表達式時,可以將 => 部分看成 “goes to” 。

匿名方法中控制返回語句的規則同樣適用於 Lambda 表達式 : 如果返回類型是 void ,就不能從 Lambda 表達式返回一個值;如果有一個非 void 的返回類型,那麼每個代碼路徑都必須返回一個兼容的值。

對於沒有返回類型的委託,如果只有一條語句,也可以使用這種語法,基本上省略分號和大括號。

表達式,不使用大括號,不使用 return 語句,也不添加分號 : { 顯式類型的參數列表 } => 表達式 。

編譯器大多數時候都能猜出參數類型,不需要你顯式聲明它們。在這種情況下,可以將 Lambda 表達式寫成 : ( 隱式類型的參數列表 ) => 表達式 。

隱式類型的參數列表就是一個以逗號分隔的名稱列表,沒有類型。但隱式和顯式類型的參數不能混合和匹配 —— 要麼整個列表都是顯式類型的,要麼全部都是隱式類型的。除此之外,如果有任何 out 或 ref 參數,就只能使用顯式類型。

(P198)

如果 Lambda 表達式只需一個參數,而且那個參數可以隱式指定類型, C# 3 就允許省略圓括號。這種格式的 Lambda 表達式是 : 參數名 => 表達式 。

是否爲 Lambda 表達式的主體使用較短的形式 (指定一個表達式來取代一個完整的代碼塊) ,以及是使用顯式還是隱式參數,這兩個決定是完全獨立的。

(P202)

.NET 3.5 的表達式樹提供了一種抽象的方式將一些代碼表示成一個對象樹。

C# 3 對於將 Lambda 表達式轉換成表達式樹提供了內建的支持。

(P205)

Lambda 表達式能顯式或隱式地轉換成恰當的委託實例。

並非所有 Lambda 表達式都能轉換成表達式樹。不能將帶有一個語句塊 (即使只有一個 return 語句) 的 Lambda 轉換成一個表達式樹 —— 只有對單個表達式進行求值的 Lambda 纔可以。

(P208)

沒有 Lambda 表達式,表達式樹幾乎沒有任何價值。

從一定程度上說,反過來說也是成立的 : 沒有表達式樹, Lambda 表達式肯定就沒那麼有用了。

(P218)

匿名函數是匿名方法和 Lambda 表達式的統稱。

(P219)

Lambda 表達式要想被編譯器理解,所有參數的類型必須爲已知。

在 C# 3 中, Lambda 表達式幾乎完全取代了匿名方法。當然,爲了保持向後兼容,匿名方法仍是支持的。

【第10章】

(P220)

C# 3 引入了擴展方法的概念,它既有靜態方法的優點,又使調用它們的代碼的可讀性得到了增強。使用擴展方法,可以像調用完全不同的類的實例方法那樣調用靜態方法。

(P223)

並不是任何方法都能作爲擴展方法使用 —— 它必須具有以下特徵 :

  1. 它必須在一個非嵌套的、非泛型的靜態類中 (所以必須是一個靜態方法) ;

  2. 它至少要有一個參數;

  3. 第一個參數必須附加 this 關鍵字作爲前綴;

  4. 第一個參數不能有其他任何修飾符 (比如 out 或 ref) ;

  5. 第一個參數的類型不能是指針類型;

(P226)

實例方法肯定會先於擴展方法使用。

在 C# 中,在空引用上調用實例方法是不允許的。

可以在空引用上調用擴展方法。

(P227)

在框架中,擴展方法最大的用途就是在 LINQ 中使用。

(P229)

Where 擴展方法是對集合進行篩選的一種簡單但又十分強大的方式 : 它接受一個謂詞,後者應用於原始集合中的每個元素。 Where 同樣返回一個 IEnumerable<T> ,但這一次所有與謂詞匹配的元素都被包括到結果集合中。

(P230)

“返回相同的引用” 模式用於易變類型,而 “返回新實例 (該實例爲原始實例更改後的副本)” 模式則用於不易變類型。

(P233)

LINQ 操作符是無副作用的 : 它們不會影響輸入,也不會改變環境。

(P236)

C# 3 只支持擴展方法而不支持擴展屬性,這稍微限制了流暢接口。

(P239)

我們學東西不應過於急功近利 —— 每次都是爲了解決當前的一個實際問題纔去學習。

在軟件工程領域,新的模式和實踐準則層出不窮,來自一些系統的設計思想經常會 “流竄” 到另一些系統中。這其實是讓軟件開發始終保持新鮮感的原因之一。

【第11章】

(P241)

序列是 LINQ 的基礎。

(P251)

Cast 通過把每個元素都轉換爲目標類型 (遇到不是正確類型的任何元素的時候,就會出錯) 來處理,而 OfType 首先進行一個測試,以跳過任何具有錯誤類型的元素。

(P254)

編譯器會故意生成一個對 Select 方法的調用,即使它什麼都沒有做。

查詢表達式的結果和源數據從來就不是同一個對象,除非 LINQ 提供器的代碼有問題。從數據集成的角度看,這是很重要的 —— 提供器能返回一個易變的結果對象,並知道即使面對一個退化查詢,對返回數據集的改變也不會影響到 “主” 數據。

(P255)

OrderBy 和 ThenBy 不同之處非常簡單 : OrderBy 假設它對排序規則起決定作用,而 ThenBy 可理解爲對之前的一個或多個排序規則起輔助作用。

(P256)

儘管你能使用多個 orderby 子句,但每個都會以它自己的 OrderBy 或 OrderByDescending 子句作爲開始,這意味着最後一個纔會真正 “獲勝” 。

let 子句只不過引入了一個新的範圍變量,它的值是基於其他範圍變量。語法是極其簡單的 : let 標識符 = 表達式 。

(P258)

let 子句使用對 Select 的另一個調用,爲結果序列創建匿名方法,並最終創建了一個新的範圍變量 (它的名稱在源代碼中從未看到或用到) 來實現目標。

(P260)

如果你打算把一個巨大的序列聯接到一個極小的序列上,應儘可能把小序列作爲右邊序列。

(P261)

通常,你希望過濾序列,而在聯接前進行過濾比在聯接後過濾要有效得多。

內聯接可用在 SQL 的所有地方,它們實際上是從某個實體導航到相關聯的實體上的一種方式,通常是把某個表的外鍵和另外一個表的主鍵進行聯接。

(P264)

交叉聯接不在序列之間執行任何匹配操作 : 結果包含了每個可能的元素對。

(P268)

分組表達式通過分組鍵決定了序列如何分組。整個結果就是一個序列,序列中的每個元素本身就是投影后元素的序列,還具有一個 Key 屬性,這就是那個用於分組的鍵;這樣的組合是封裝在 IGrouping<TKey, TElement> 接口中的,它擴展了 IEnumerable<TElement> 。

(P270)

查詢延續提供一種方式,把一個查詢表達式的結果用作另外一個查詢表達式的初始序列。它可以應用於 group...by 和 select 子句上,語法對於兩者是一樣的 —— 你只需使用上下文關鍵字 into ,併爲新的範圍變量提供一個名稱就可以了。範圍變量接着能用在查詢表達式的下一部分。

【第12章】

(P277)

LINQ to SQL 需要有關數據庫的元數據,來知道哪個類與哪個數據庫表相對應等信息。可以用幾種不同的方式來表示這種元數據,而我這裏使用的是 Visual Studio 內嵌的 LINQ to SQL 設計器。

【第13章】

(P312)

參數 (也稱爲形式參數) 變量是方法或索引器聲明的一部分,而實參是調用方法或索引器時使用的表達式。

(P313)

如果某個操作需要多個值,而有些值在每次調用的時候又往往是相同的,這時通常可以使用可選參數。

(P314)

指定了默認值的參數爲可選參數。

(P315)

可選參數包含一些規則。所有可選參數必須出現在必備參數之後,參數數組 (用 params 修飾符聲明) 除外,但它們必須出現在參數列表的最後,在它們之前爲可選參數。參數數組不能聲明爲可選的,如果調用者沒有指定值,將使用空數組代替。可選參數不能使用 ref 或 out 修飾符。

(P316)

基本上,你必須使用永遠不會改變的真正常量作爲可選參數的默認值。

(P318)

如果要對包含 ref 或 out 的參數指定名稱,需要將 ref 或 out 修飾符放在名稱之後,實參之前。

(P319)

實參是按照參數的名稱來匹配的,而不再是參數的位置。

未命名的實參稱爲位置實參。

所有命名實參都必須位於位置實參之後,兩者之間的位置不能改變。位置實參總是指向方法聲明中相應的參數 —— 你不能跳過參數之後,再通過命名相應位置的實參來指定。

(P331)

可變性有兩種類型 : 協變性和逆變性。

協變性用於向調用者返回某項操作的值。

逆變性則相反。它指的是調用者向 API 傳入的值,即 API 是在消費值,而不是產生值。

(P332)

在泛型接口或委託聲明中, C# 4 能夠使用 out 修飾符來指定類型參數的協變性,使用 in 修飾符來指定逆變性。

任何使用了協變和逆變的轉換都是引用轉換,這意味着轉換之後將返回相同的引用。它不會創建新的對象,只是認爲現有引用與目標類型匹配。

如果類型參數只用於輸出,就使用 out ,如果只用於輸入,就用 in 。

(P337)

只有接口和委託可以擁有可變的類型參數。即使類中包含只用於輸入 (或只用於輸出) 的類型參數,仍然不能爲它們指定 in 或 out 修飾符。

【第14章】

(P345)

事實上, dynamic 並不代表一個特定的 CLR 類型,它實際上只是包含 System.Dynamic.DynamicAttribute 特性的 System.Object 。

(P347)

dynamic 可用來聲明類型的字段、參數和返回值。這與 var 形成了鮮明的對比,後者只能用於局部變量。

(P355)

如果兩個方法的簽名包含的參數類型相同,編譯器將選擇非泛型重載,而不是泛型重載。

(P362)

dynamic 類型的參數將被視爲 object 類型 —— 如果查看編譯後的代碼,將發現它確實爲 object 類型的參數,只不過應用了額外的特性。這還意味着在你聲明的方法中,它們的簽名不能只以 dynamic / object 參數類型來進行區分。

(P369)

你不能聲明一個基類爲 dynamic 的類型,你同樣不能將 dynamic 用於類型參數的約束,或作爲類型所實現的接口的一部分。你可以將其用於基類的類型實參,或在聲明變量時將其用於接口。
**

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章