《C# 6.0 本質論》 - 學習筆記

来源:https://www.cnblogs.com/GATTACA2011/archive/2020/02/18/12327013.html

《C# 6.0 本質論》 [作者] (美) Mark Michaelis (美) Eric Lippert[譯者] (中) 周靖 龐燕[出版] 人民郵電出版社[版次] 2017年02月 第5版[印次] 2017年02月 第1次 印刷[定價] 108.00元 【前言】 成功學習 C# 的關鍵在於,要盡 ...


《C# 6.0 本質論》

========== ========== ==========
[作者] (美) Mark Michaelis (美) Eric Lippert
[譯者] (中) 周靖 龐燕
[出版] 人民郵電出版社
[版次] 2017年02月 第5版
[印次] 2017年02月 第1次 印刷
[定價] 108.00元
========== ========== ==========

【前言】

成功學習 C# 的關鍵在於,要儘可能快地開始編程。不要等自己成為一名理論方面的 “專家” 之後,才開始寫代碼。

學習一門電腦語言最好的方法就是在動手中學習,而不是等熟知了它的所有 “理論” 之後再動手。

為了從簡單程式過渡到企業級開發, C# 開發者必須熟練地從對象及其關係的角度來思考問題。

一名知道語法的程式員和一名能因時宜地寫出最高效代碼的專家的區別,關鍵就是這些編碼規範。專家不僅讓代碼通過編譯,還遵循最佳實踐,降低產生 bug 的概率,並使代碼的維護變得更容易。編碼規範強調了一些關鍵原則,開發時務必註意。

總地說來,軟體工程的宗旨就是對複雜性進行管理。

【第01章】

(P001)

學習新語言最好的辦法就是動手寫代碼。

(P003)

一次成功的 C# 編譯生成的肯定是程式集,無論它是程式還是庫。

在 Java 中,文件名必須和類名一致。

從 C# 2.0 開始,一個類的代碼可以拆分到多個文件中,這一特性稱為 “部分類” 。

編譯器利用關鍵字來識別代碼的結構與組織方式。

(P004)

C# 1.0 之後沒有引入任何新的保留關鍵字,但在後續版本中,一些構造使用了上下文關鍵字 (contextual keyword) ,它們在特定位置才有意義。除了那些位置,上下文關鍵字沒有任何特殊意義。這樣,大多數的 C# 1.0 代碼都完全相容於後續的版本。

分配標識符之後,以後就能用它引用所標識的構造。因此,開發人員應分配有意義的名稱,不要隨意分配。

好的程式員總能選擇簡潔而有意義的名稱,這使代碼更容易理解和重用。

(P005)

[規範]

1. 要更註重標識符的清晰而不是簡短;

2. 不要在標識符名稱中使用單詞縮寫;

3. 不要使用不被廣泛接受的首字母縮寫詞,即使被廣泛接受,非必要時也不要用;

下劃線雖然合法,但標識符一般不要包含下劃線、連字元或其他非 字母 / 數字 字元。

[規範]

1. 要把只包含兩個字母的首字母縮寫詞全部大寫,除非它是駝峰大小寫風格標識符的第一個單詞;

2. 包含 3 個或更多字母的首字母縮寫詞,僅第一個字母才要大寫,除非該縮寫詞是駝峰大小寫風格標識符的第一個單詞;

3. 在駝峰大小寫風格標識符開頭的首字母縮寫詞中,所有字母都不要大寫;

4. 不要使用匈牙利命名法 (也就是,不要為變數名稱附加類型首碼) ;

關鍵字附加 “@” 首碼可作為標識符使用。

C# 中所有代碼都出現在一個類型定義的內部,最常見的類型定義是以關鍵字 class 開頭的。

(P006)

對於包含 Main() 方法的類, Program 是個很好的名稱。

[規範]

1. 要用名詞或名詞短語命名類;

2. 要為所有類名使用 Pascal 大小寫風格;

一個程式通常包含多個類型,每個類型都包含多個方法。

方法可以重用,可以在多個地方調用,所以避免了代碼的重覆。

方法聲明除了負責引入方法之外,還要定義方法名以及要傳入和傳出方法的數據。

C# 程式從 Main 方法開始執行,該方法以 static void Main() 開頭。

程式會啟動並解析 Main 的位置,然後執行其中第一條語句。

雖然 Main 方法聲明可以進行某種程度的改變,但關鍵字 static 和方法名 Main 是始終都是程式必需的。

C# 要求 Main 方法的返回類型為 void 或 int ,而且要麼不帶參數,要麼接收一個字元串數組作為參數。

(P007)

args 參數是一個字元串數組,用於接收命令行參數。

Main 返回的 int 值是狀態碼,標識程式執行是否成功。返回非零值通常意味著錯誤。

C# 的 Main 方法名使用大寫 M ,以便與 C# 的 Pascal 大小寫風格命名約定保持一致。

Main() 之前的 void 表明該方法不返回任何數據。

C# 通常用分號標識語句結束,每條語句都由代碼要執行的一個或多個行動構成。

由於換行與否不影響語句的分隔,所以可以將多條語句放到同一行, C# 編譯器會認為這一行包含多條指令。

C# 還允許一條語句跨越多行。同樣地, C# 編譯器會根據分號判斷語句的結束位置。

(P008)

分號使 C# 編譯器能忽略代碼中的空白。除了少數例外情況, C# 允許在代碼中隨意插入空白而不改變其語義。

空白是一個或多個連續的格式字元 (如製表符、空格和換行符) 。刪除單詞間的所有空白肯定會造成歧義。刪除引號字元串中的任何空白也會造成歧義。

程式員經常利用空白對代碼進行縮進來增強可讀性。

為了增強可讀性,利用空白對代碼進行縮進是非常重要的。寫代碼時要遵循已經建立的編碼標準和約定,以增強代碼的可讀性。

(P009)

聲明變數就是定義它,需要 :

1. 指定變數要包含的數據的類型;

2. 為它分配標識符 (變數名) ;

一個變數聲明所指定的數據的類型稱為數據類型。數據類型,或者簡稱為類型,是具有相似特征和行為的個體的分類。

在編程語言中,類型是被賦予了相似特性的一些個體的定義。

(P010)

局部變數名採用的是駝峰大小寫風格命名 (即除了第一個單詞,其他的每個單詞的首字母大寫) ,而且不包含下劃線。

[規範]

1. 要為局部變數使用 camel 大小寫風格的命名;

局部變數聲明後必須在引用之前為其賦值。

C# 允許在同一條語句中進行多個賦值操作。

(P011)

賦值後就能用變數標識符引用值。

所有 string 類型的數據,不管是不是字元串字面量,都是不可變的 (或者說是不可修改的) 。也就是說,不能修改變數最初引用的數據,只能重新為變數賦值,讓它引用記憶體中的新位置。

System.Console.ReadLine() 方法的輸出,也稱為返回值,就是用戶輸入的文本字元串。

(P012)

System.Console.Read() 方法返回的是與讀取的字元值對應的整數,如果沒有更多的字元可用,就返回 -1 。為了獲取實際字元,需要先將整數轉型為字元。

除非用戶按回車鍵,否則 System.Console.Read() 方法不會返回輸入。按回車鍵之前不會對字元進行處理,即使用戶已經輸入了多個字元。

C# 2.0 以上的版本可以使用 System.Console.ReadKey() 方法。它和 System.Console.Read() 方法不同,用戶每按下一個鍵就返回用戶所按的鍵。可用它攔截用戶按鍵操作,並執行相應行動,如校驗按鍵,限制只能按數字鍵。

(P013)

在字元串插值中,編譯器將字元串花括弧中的部分解釋為可以嵌入代碼 (表達式) 的區域,編譯器將對嵌入的表達式估值並將其轉換為字元串。字元串插值不需要先逐個執行很多個代碼片段,最後再將結果組合成字元串,它可以一步完成這些輸出。這使得代碼更容易理解。

C# 6.0 之前的版本利用的是複合格式化 (composite formatting) 來進行一次性輸出。在複合格式化中,代碼首先提供格式字元串 (format string) 來定義輸出格式。

(P014)

占位符在格式字元串中不一定按順序出現。

占位符除了能在格式字元串中按任意順序出現之外,同一個占位符還能在一個格式字元串中多次使用。

(P015)

[規範]

1. 不要使用註釋,除非代碼本身 “一言難盡” ;

2. 要儘量編寫清晰的代碼,而不是通過註釋澄清複雜的演算法;

(P016)

在 .NET 中,一個程式集包含的所有類型 (以及這些類型的成員) 構成這個程式集的 API 。

同樣,對於程式集的組合,例如 .NET Framework 中的程式集組合,每個程式集的 API 組合在一起構成一個更大的 API 。這個更大的 API 組通常被稱為框架 (framework) , .NET Framework 就是指 .NET 包含的所有程式集對外暴露的 API 。

一般地, API 包括一系列介面和協議 (或指令) ,它們定義了程式和一組部件交互的規則。實際上,在 .NET 中,協議本身就是 .NET 程式集執行的規則。

(P017)

一個公共編程框架,稱為基類庫 (Base Class Library , BCL) ,提供開發者能夠 (在所有 CLI 實現中) 依賴的大型代碼庫,使他們不必親自編寫這些代碼。

(P018)

.NET Core 不同於完整的 .NET Framework 功能集,它包含了整個 (ASP.NET) 網站可以在 Windows 之外的操作系統上部署所需的功能以及 IIS (Internet Information Server , 網際網路信息伺服器) 。這意味著,同樣的代碼可以被編譯和執行成跨平臺運行的應用程式。

.NET Core 包含了 .NET 編譯平臺 (“Roslyn”) 、 .NET Core 運行時、 .NET 版本管理 (.NET Version Manager , DNVM) 以及 .NET 執行環境 (.NET Execution Environment , DNX) 等工具,可以在 Linux 和 OS X 上執行。

(P020)

事實上,一些免費工具 (如 Red Gate Reflector 、 ILSpy 、 JustDecompile 、 dotPeek 和 CodeReflect) 可以將 CIL 自動反編譯成 C# 。

【第02章】

(P022)

C# 有幾種類型非常簡單,被視為其他所有類型的基礎。這些類型稱為預定義類型 (predefined type) 。

C# 語言的預定義類型包括 8 種整數類型、 2 種用於科學計算的二進位浮點類型、 1 種用於金融計算的十進位浮點類型、 1 種布爾類型以及 1 種字元類型。

decimal 是一種特殊的浮點類型,能夠存儲大數值而無表示錯誤。

(P023)

C# 的所有基本類型都有短名稱和完整名稱。完整名稱對應於 BCL (Base Class Library , 基類庫) 中的類型命名。

由於基本數據類型是其他類型的基礎,所以 C# 為基本數據類型的完整名稱提供了短名稱或縮寫的關鍵字。

C# 開發人員一般選擇使用 C# 關鍵字。

[規範]

1. 要在指定數據類型時使用 C# 關鍵字而不是 BCL 名稱 (例如,使用 string 而不是 String) ;

2. 要保持一致而不要變來變去;

(P024)

浮點數的精度是可變的。

與浮點數不同, decimal 類型保證範圍內的所有十進位數都是精確的。

雖然 decimal 類型具有比浮點類型更高的精度,但它的範圍較小。

decimal 的計算速度稍慢 (雖然這個差別可以忽略不計) 。

除非超過範圍,否則 decimal 數字表示的十進位數都是完全準確的。

(P025)

預設情況下,輸入帶小數點的字面量,編譯器會自動把它解釋成 double 類型。

整數值 (沒有小數點) 通常預設為 int ,但前提是該值不要太大,以至於無法用 int 來存儲。

要顯示具有完整精度的數字,必須將字面量顯式聲明為 decimal 類型,這是通過追加一個 M (或者 m) 尾碼來實現的。

(P026)

d 表示 double ,之所以用 m 表示 decimal ,是因為這種數據類型經常用於貨幣 (monetary) 計算。

對於整數數據類型,相應的尾碼是 U 、 L 、 LU 和 UL 。整數字面量的類型是像下麵這樣確定的 :

1. 沒有尾碼的數值字面量按照以下順序,解析成能夠存儲該值的第一種數據類型 : int 、 uint 、 long 、 ulong ;

2. 具有尾碼 U 的數值字面量按照以下順序,解析成能夠存儲該值的第一種數據類型 : uint 、 ulong ;

3. 具有尾碼 L 的數值字面量按照以下順序,解析成能夠存儲該值的第一種數據類型 : long 、 ulong ;

4. 如果數值字面值的尾碼是 UL 或 LU ,則解析成 ulong 類型;

註意,字面量的尾碼不區分大小寫。但對於 long ,一般推薦使用大寫字母 L ,因為小寫字母 l 和數字 1 不好區分。

[規範]

1. 要使用大寫的字面量尾碼;

2. 十六進位和十進位的相互轉換不會改變數本身,改變的只是數的表示形式;

(P027)

要以十六進位形式輸出一個數值,必須使用 x 或 X 數值格式說明符。大小寫決定了十六進位字母的大小寫。

(P028)

雖然從理論上說,一個二進位位就足以容納一個布爾類型的值,但 bool 數據類型的實際大小是一個位元組。

字元類型 char 表示 16 位字元,其取值範圍對應於 Unicode 字元集。

從技術上說, char 的大小和 16 位無符號整數 (ushort) 相同,後者的取值範圍是 0 ~ 65535 。

(P029)

為了輸入 char 類型的字面量,需要將字元放到一對單引號中。

反斜杠和特殊字元代碼組成轉義序列 (escape sequence) 。

可以使用 Unicode 代碼表示任何字元。為此,請為 Unicode 值附加 \u 首碼。

(P030)

零或多個字元組成的有限序列稱為字元串。

為了將字面量字元串輸入代碼,要將文本放入雙引號 (") 內。

字元串由字元構成,所以轉義序列可以嵌入字元串內。

雙引號要用轉義序列輸出,否則會被用於定義字元串開始與結束。

在 C# 中,可以在字元串前面使用 @ 符號,指明轉義序列不被處理。

結果是一個逐字字元串字面量 (verbatim string literal) ,它不僅將反斜杠當作普通字元處理,還會逐字解釋所有空白字元。

(P031)

在以 @ 開頭的字元串中,唯一支持的轉義序列是 "" ,它代表一個雙引號,這個雙引號不會終止字元串。

假如同一個字元串字面量在程式集中多次出現,編譯器在程式集中只定義字元串一次,且所有變數都將指向同一個字元串。

通過使用字元串插值格式,字元串可以支持嵌入的表達式。字元串插值語法在一個字元串字面量前加上一個 $ 符號首碼,然後將表達式嵌入大括弧中。

註意,字元串字面量可以通過在 “@” 符號前加上 “$” 符號的字元串插值組合而成。

(P032)

字元串插值是調用 string.Format() 方法的簡寫。

(P033)

string.Format() 不是在控制台視窗中顯示結果,而是返回結果。

增加了字元串插值功能之後, string.Format() 的重要性減弱了不少 (除了對本地化功能的支持) 。在後臺,字元串插值是利用了 string.Format() 編譯成 CIL 的。

目前靜態方法的調用通常是包含一個命名空間的首碼後面跟類型名。

(P034)

using static 指令必須放在文件的最開始。

using static 指令只對靜態方法和屬性有效,對於實例成員不起作用。

using 指令與 using static 指令類似,使用後也可以省略命名空間首碼。與 using static 指令不同的是, using 指令在文件 (或命名空間) 中應用非常普遍,不僅只應用於靜態成員。無論是實例化,或是靜態方法調用,抑或是使用 C# 6.0 中新增的 nameof 操作符時,使用 using 指令都可以隨意地省略所有的命名空間引用。

無論是使用 string.Format() 還是用 C# 6.0 的字元串插值功能構造複雜格式的字元串,總要用一組豐富的、複雜的格式模板來顯示數字、日期、時間、時間段等等。

如果想在一個插值的字元串或格式化的字元串中真正出現左大括弧或者右大括弧,可以通過連續輸入兩個大括弧表明這個大括弧不是引入的格式模板。

輸出新行所需的字元取決於執行代碼的操作系統。

(P035)

字元串的長度不能直接設置,它是根據字元串中的字元數計算得到的。此外,字元串的長度不能更改,因為字元串是不可變的。

string 類型的關鍵特征在於它是不可變的 (immutable) 。

(P036)

與類型有關的兩個額外的關鍵字是 null 和 void 。 null 值由關鍵字 null 標識,表明變數不引用任何有效的對象。 void 表示沒有類型,或者沒有任何值。

(P037)

null 也可以作為字元串字面量的類型使用。 null 表示將變數設為 “無” 。 null 值只能賦給引用類型、指針類型和可空值類型。

將變數設為 null ,會顯式地設置引用,使它不指向任何位置。

必須註意,和根本不賦值相比,將 null 賦給引用類型的變數是完全不同的概念。換言之,賦值為 null 的變數已被設置,而未賦值的變數未被設置,所以假如在賦值前使用變數會造成編譯時錯誤。

將 null 值賦給一個 string 變數,並不等同於將空字元串 "" 賦給它。 null 意味著變數無任何值,而 "" 意味著變數有一個稱為 “空字元串” 的值。這種區分相當有用。

在返回類型的位置使用 void 意味著方法不返回任何數據,同時告訴編譯器不要期望會有一個值。 void 本質上並不是一個數據類型,它只是用於指出沒有數據返回這一事實。

(P038)

C# 3.0 新增了上下文關鍵字 var 來聲明隱式類型的局部變數。

雖然允許使用 var 取代顯式的數據類型,但在數據類型已知的情況下最好不要使用 var 。

用 var 聲明變數,右側的數據類型應該是非常明顯的;否則應該考慮避免使用 var 聲明。

C# 3.0 添加 var 的目的是支持匿名類型。匿名類型是在方法內部動態聲明的數據類型,而不是通過顯式的類定義來聲明的。

(P039)

所有類型都可以歸為值類型或引用類型。它們的區別在於複製方式 : 值類型的數據總是進行值複製,而引用類型的數據總是進行引用複製。

值類型變數直接包含值。換言之,變數引用的位置就是值在記憶體中實際存儲的位置。因此,將第一個變數的值賦給第二個變數會在新變數的位置創建原始變數的值的一個記憶體副本。相同值類型的第二個變數不能引用和第一個變數相同的記憶體位置。所以,更改第一個變數的值不會影響第二個變數的值。

由於值類型需要創建記憶體副本,因此定義時不要讓它們占用太多記憶體 (通常應該小於 16 位元組) 。

(P040)

引用類型的值存儲的是對數據存儲位置的引用,而不是直接存儲數據。要去那個位置才能找到真正的數據。因此,為了訪問數據, “運行時” 要先從變數中讀取記憶體位置,再 “跳轉” 到包含數據的記憶體位置。引用類型指向的記憶體區域稱堆 (heap) 。

引用類型不像值類型那樣要求創建數據的記憶體副本,所以複製引用類型的實例比複製大的值類型實例更高效。

將引用類型的變數賦給另一個引用類型的變數,只會複製引用而不需要複製所引用的數據。

事實上,每個引用總是處理器的 “原生大小” 。也就是, 32 位處理器只需複製 32 位引用, 64 位處理器只需複製 64 位引用,以此類推。

顯然,複製對一個大數據塊的引用,比複製整個數據塊快得多。

由於引用類型只複製對數據的引用,所以兩個不同的變數可引用相同的數據。

如果兩個變數引用同一個對象,利用一個變數更改對象的欄位,用另一個對象訪問欄位時將看到更改結果。無論賦值還是方法調用都會如此。

在決定定義引用類型還是值類型時,一個決定性的因素就是 : 如果對象在邏輯上是固定大小的不可變的值,就考慮定義成值類型;如果邏輯上是可引用的可變的對象,就考慮定義成引用類型。

(P041)

一般不能將 null 值賦給值類型。這是因為根據定義,值類型不能包含引用,即使是對 “無 (nothing)” 的引用。

為了聲明可以存儲 null 的變數,要使用可空修飾符 (?) 。

將 null 賦給值類型,這在資料庫編程中尤其有用。

有可能造成大小變小或者引發異常 (因為轉換失敗) 的任何轉換都需要執行顯式轉型 (explicit cast) 。相反,不會變小,而且不會引發異常 (無論操作數的類型是什麼) 的任何轉換都屬於隱式轉型 (implicit cast) 。

在 C# 中,可以使用轉型操作符執行轉型。通過在圓括弧中指定希望變數轉換成的類型,表明你已認可在發生顯式轉型時可能丟失精度和數據,或者可能造成異常。

(P043)

C# 還支持 unchecked 塊,它強制不進行溢出檢查,不會為塊中溢出的賦值引發異常。

即使編譯時打開了 checked 選項,在執行期間, unchecked 關鍵字也會阻止 “運行時” 引發異常。

(P044)

即使不要求顯式轉換操作符 (因為允許隱式轉型) ,仍然可以強制添加轉型操作符。

每個數值數據類型都包含一個 Parse() 方法,它允許將字元串轉換成對應的數值類型。

可利用特殊類型 System.Convert 將一種類型轉換成另一種類型。

System.Convert 只支持小的數據類型,而且是不可擴展的。它允許從 bool 、 char 、 sbyte 、 short 、 int 、 long 、 ushort 、 uint 、 ulong 、 float 、 double 、 decimal 、 DateTime 和 string 類型中的任何一種類型轉換到另一種類型。

所有類型都支持 ToString() 方法,可以用它提供一個類型的字元串表示。

(P045)

對於大多數類型, ToString() 方法只是返回數據類型的名稱,而不是數據的字元串表示。只有在類型顯式實現了 ToString() 的前提下才會返回字元串表示。

從 C# 2.0 (.NET 2.0) 開始,所有基元數值類型都包含靜態 TryParse() 方法。該方法與 Parse() 非常相似,只是轉換失敗的情況下,它不引發異常,而是返回 false 。

Parse() 和 TryParse() 的關鍵區別在於,假如轉換失敗, TryParse() 不會引發異常。

C# 中的數組是基於零的。

數組中每個數據項都使用名為索引的整數值進行唯一性標識。 C# 數組中的第一個數據項使用索引 0 訪問。

程式員應確保指定的索引值小於數組的大小 (數組中的元素總數) 。

因為 C# 數組是基於零的,所以數組最後一個元素的索引值要比數組元素的總數小 1 。

(P046)

初學者可將索引想象成偏移量。第一項距離數組開頭的偏移量是 0 ,第二項的偏移量是 1 ,依次類推。

數組是幾乎每一種編程語言的基本組成部分,因此所有開發人員都要學會它。

在 C# 中,使用方括弧聲明數組變數。首先要指定數組元素的類型,後跟一對方括弧,再輸入變數名。

在 C# 中,作為數組聲明一部分的方括弧是緊跟在數據類型之後的,而不是出現在變數聲明之後。

(P047)

使用更多的逗號,可以定義更多的維。數組總維數等於逗號數加 1 。

數組如果在聲明後賦值,則需要使用 new 關鍵字。

(P048)

自 C# 3.0 起,不必在 new 後面指定數組的數據類型,只要編譯器能根據初始化列表中的數據類型推斷出數組元素的類型。但是,方括弧仍然不可缺少。

只要將 new 關鍵字作為數組賦值的一部分,就可以同時在方括弧內指定數組的大小。

在初始化語句中指定的數組的大小必須和大括弧中包含的元素數量相匹配。

從 C# 2.0 開始可以使用 default() 表達式判斷數據類型的預設值。 default() 獲取數據類型作為參數。

由於數組大小不需要作為變數聲明的一部分,所以可以在運行時指定數組大小。

(P050)

多維數組的每一維的大小都必須一致。

交錯數組不使用逗號標識新的維。相反,交錯數組定義由數組構成的數組。

註意,交錯數組要求內部的每個數組都創建數組實例。

(P051)

數組的長度是固定的,不能隨便更改,除非重新創建數組。

Length 成員返回數組中數據項的個數,而不是返回最高的索引值。

為了將 Length 作為索引來使用,有必要在它上面減 1 ,以避免越界錯誤。

(P052)

Length 返回數組中元素的總數。

對於交錯數組, Length 返回的是外部數組的元素數。

(P053)

使用 System.Array.BinarySearch() 方法前要對數組進行排序。

System.Array.Clear() 方法不刪除數組元素,而且不將長度設為零。

System.Array.Clear() 方法將數組中的每個元素都設為其預設值。

要獲取特定維的長度不是使用 Length 屬性,而是使用數組的 GetLength() 實例方法。

(P054)

可以訪問數組的 Rank 成員來獲取整個數組的維數。

預設情況下,將一個數組變數賦值給另一個數組變數只會複製數組引用,而不是數組中單獨的元素。要創建數組的全新副本,需使用數組的 Clone() 方法。該方法返回數組的一個副本,更改這個新數組中的任何成員都不會影響原始數組的成員。

可以使用字元串的 ToCharArray() 方法,將整個字元串作為字元數組返回。

(P055)

用於聲明數組的方括弧放在數據類型之後,而不是在變數標識符之後。

(P056)

如果是在聲明之後再對數組進行賦值,需要使用 new 關鍵字,並可選擇指定數據類型。

不能在變數聲明中指定數組大小。

除非提供數組字面量,否則必須在初始化時指定數組大小。

數組的大小必須與數組字面量中的元素個數相符。

【第03章】

(P058)

通常將操作符劃分為 3 大類 : 一元操作符、二元操作符和三元操作符,它們對應的操作數分別是 1 個、 2 個和 3 個。

使用負操作符 (-) 等價於從零減去操作數。

一元正操作數 (+) 對值幾乎沒有影響。它在 C# 語言中是多餘的,只是出於對稱性的考慮才加進來。

二元操作符要求兩個操作數。 C# 為二元操作符使用中綴表示法 : 操作符在左、右操作數之間。每個二元表達式的結果要麼賦給一個變數,要麼以某種方式使用 (例如用作為另一個表達式的操作數) 。

在 C# 中,只有調用、遞增、遞減和對象創建表達式才能作為獨立的語句使用。

一元 (+) 操作符定義為獲取 int 、 uint 、 long 、 ulong 、 float 、 double 和 decimal 類型 (及其可空版本) 的操作數。用於其他類型 (如 short ) 時,操作數會根據實際情況轉換為上述某個類型。

算數操作符的每一邊都有一個操作數,計算結果賦給一個變數。

(P059)

圓括弧可以明確地將一個操作數與它所屬的操作符相關聯。

(P060)

C# 的大多數操作符都是左結合的,賦值操作符右結合。

有時候,圓括弧操作符並不改變表達式的求值結果。不過,使用圓括弧來提高代碼的可讀性依然是一良好的編程的習慣。

[規範]

1. 要使用圓括弧增加代碼的易讀性,尤其是在操作符優先順序不是讓人一目瞭然的時候;

在 C# 中,操作數總是從左向右求值。

操作符也可用於非數值類型。例如,可以使用加法操作符來拼接兩個或者更多字元串。

(P061)

當必須進行本地化時,應該有節制地使用加法操作符,最好使用組合格式化。

[規範]

1. 當必須進行本地化時,要用組合格式化而不是加法操作符來拼接字元串;

雖然 char 類型存儲的是字元而不是數字,但它是整型 (意味著它基於整數) ,可以和其他整型一起參與算數運算。然而,不是基於存儲的字元來解釋 char 類型的值,而是基於它的基礎值。

可以利用 char 類型的這個特點判斷兩個字元相距多遠。

(P062)

二進位浮點類型實際存儲的是二進位分數而不是十進位分數。所以,一次簡單的賦值就可能引發精度問題。

[規範]

1. 避免在需要準確的十進位算術運算時使用二進位浮點類型,而是使用 decimal 浮點類型;

比較兩個值是否相等的時候,浮點類型的不准確性可能造成非常嚴重的後果。

(P063)

[規範]

1. 避免將二進位浮點類型用於相等性條件式。要麼判斷兩個值之差是否在容差範圍之內,要麼使用 decimal 類型;

(P064)

(+=) 操作符使左邊的變數遞增右邊的值。

(P065)

賦值操作符還可以和減法、乘法、除法和取餘操作符結合。

C# 提供了特殊的一元操作符來實現計數器的遞增和遞減。遞增操作符 (++) 每次使一個變數遞增 1 。

可以使用遞減操作符 (--) 使變數遞減 1 。

遞增和遞減操作符在迴圈中經常用到。

(P066)

遞增和遞減操作符用於控制特定操作的執行次數。

只要數據類型支持 “下一個值” 和 “上一個值” 的概念,就適合使用遞增和遞減操作符。

遞增或遞減操作符的位置決定了所賦的值是操作數計算之前還是之後的值。

(P067)

遞增和遞減操作符相對於操作數的位置影響了表達式的結果。首碼操作符的結果是變數 遞增 / 遞減 之後的值,而尾碼操作符的結果是變數 遞增 / 遞減 之前的值。

[規範]

1. 避免混淆遞增和遞減操作符的用法;

(P068)

常量表達式是 C# 編譯器能在編譯時完成求值的表達式 (而不是在程式運行時才能求值) ,因為其完全由常量操作數構成。

const 關鍵字的作用就是聲明常量符號。由於常量和 “變數” 相反 —— “常” 意味著 “不可變” —— 以後在代碼中任何修改它的企圖都會造成編譯時錯誤。

[規範]

1. 不要使用常量表示將來可能改變的任何值;

(P072)

規範提倡除了單行語句之外都使用代碼塊。

使用大括弧,可以將多個語句合併成代碼塊,允許在符合條件時執行多個語句。

(P074)

事實上,設計規範規定除非是單行語句,否則不要省略大括弧。

[規範]

1. 避免在 if 語句中省略大括弧,除非只有一行語句;

總的來說,作用域決定一個名稱引用什麼事物,而聲明空間決定同名的兩個事物是否衝突。

(P075)

聲明空間中的每個局部變數名稱必須是唯一的。聲明空間覆蓋了包含在最初聲明局部變數的代碼塊中的所有子代碼塊。

(P076)

相等性操作符使用兩個等號,賦值操作符使用一個等號。

(P077)

關係和相等性操作符總是生成 bool 值。

邏輯操作符 (logic operator) 獲取布爾操作數並生成布爾結果。可以使用邏輯操作符合併多個布爾表達式來構成更複雜的布爾表達式。

(P078)

^ 符號是異或 (exclusive OR , XOR) 操作符,若應用於兩個布爾操作數,那麼只有在兩個操作數中僅有一個為 true 的前提下, XOR 操作符才會返回 true 。

條件操作符是三元操作符,因為它需要 3 個操作數,即 condition 、 consequence 和 alternative 。

作為 C# 中唯一的三元操作符,條件操作符也經常被稱為 “三元操作符” 。

(P079)

和 if 語句不同,條件操作符的結果必須賦給某個變數 (或者作為參數傳遞) 。它不能單獨作為一個語句使用。

[規範]

1. 考慮使用 if / else 語句,而不是使用過於複雜的條件表達式;

空接合操作符 (null coalescing operator) ?? 能簡單地表示 “如果這個值為空,就使用另一個值” 。

?? 操作符支持短路求值。

(P080)

空接合操作符能完美地 “鏈接” 。

空結合操作符是 C# 2.0 和可空值類型一起引入的,它的操作數既可以是可空值類型,也可以是引用類型。

C# 6.0 引入了一種更為簡化的 null 條件操作符 (null-condition operator) ?. 。

(P083)

兩個移位操作符是 >> 和 << ,分別稱為右移位和左移位操作符。除此之外,還有複合移位和賦值操作符 <<= 和 >>= 。

AND 和 OR 操作符的按位版本不進行 “短路求值” 。

(P086)

按位取反操作符 (~) 是對操作數的每一位取反,操作數可以是 int 、 uint 、 long 和 ulong 類型。

您的分享是我們最大的動力!

更多相關文章
  • [toc] 一.Java的基本數據類型介紹 | 類型 | 關鍵字 | 位數 | 預設值 | 取值範圍 | | : : | : : | : : | : : | : : | | 位元組型 | byte | 8 | 0 | 128~127 | | 短整型 | short | 16 | 0 | 32768~3 ...
  • springboot預設打包成jar,如果想打包成war,則需要做以下三步。 1.修改pom.xml文件 a.將jar改成war 1 <groupId>com.test</groupId> 2 <artifactId>01-springboot-HelloWorld</artifactId> 3 < ...
  • 下載cron包: go get github.com/robfig/cron 開啟一個定時: 根據cron表達式進行時間調度,cron可以精確到秒,大部分表達式格式也是從秒開始。 c := cron.New()預設從分開始,所以加上cron.WithSeconds(),保證定時按照表達式字面意思執行 ...
  • 1.工具類可以一次寫入多方多方調用,很大程度的節約開發時間得到想要的信息 這裡演示一個json介面的工具類(文件定義在App\Http\Controllers\Tools)中 <?php /** * Created by PhpStorm. * User: yly * Date: 2020/2/18 ...
  • 最近由於“武漢肺炎”疫情在家辦公,也沒閑著,最近學習了一下asp.net core mvc的一些網頁開發的的基礎知識,話不多說直接上教程! 一、創建Web應用程式 1)創建新項目 >找到 “ASP.NET Core Web 應用程式” 類型的項目(也可以模糊查詢:語言選擇c#,項目類型選擇Web): ...
  • 概述 ASP.NET Core可以說是處處皆註入,本文從基礎角度理解一下原生DI容器,及介紹下怎麼使用並且如何替換官方提供的預設依賴註入容器。 什麼是依賴註入 百度百科中對於依賴註入的定義: 控制反轉 (Inversion of Control,縮寫為 IoC ),是 "面向對象編程" 中的一種設計 ...
  • 在 C 中存在一個名叫靜態類型檢查的機制,這個機制可以讓編譯器幫助我們把類型不服的用法找出來,從而使得應用程式在運行期間加少一些類型檢查的操作。但是有時候我們還是需要進行運行期類型檢查,比如我們在設計框架時將方法的參數類型定義為 object ,那麼這時我們就有很大的可能需要將 object 類型的 ...
  • 本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7772184.html,記錄一下學習過程以備後續查用。 一、引言 今天我們要講結構型設計模式的第五個模式--外觀模式。先從名字上來理解一下外觀模式,當看到“外觀”這個詞時,很容易想到“外表”這個詞語,兩者有著 ...
一周排行
  • 一:背景 1. 講故事 如果你常翻看FCL的源碼,你會發現這裡面有不少方法藉助了C/C++的力量讓C#更快更強悍,如下所示: [DllImport("QCall", CharSet = CharSet.Unicode)] [SecurityCritical] [SuppressUnmanagedCo ...
  • 上一篇(https://www.cnblogs.com/meowv/p/12966092.html)文章使用AutoMapper來處理對象與對象之間的映射關係,本篇主要圍繞定時任務和數據抓取相關的知識點並結合實際應用,在定時任務中迴圈處理爬蟲任務抓取數據。 開始之前可以刪掉之前測試用的幾個Hello ...
  • 首先創建實體類 1 public class MacState 2 { 3 /// <summary> 4 /// 請求狀態 5 /// </summary> 6 public string success { get; set; } 7 /// <summary> 8 /// 錯誤信息 9 /// ...
  • 0. 前言 前幾天FreeSql的作者向我推薦了FreeSql框架,想讓我幫忙寫個文章介紹一下。嗯,想不到我也能帶個貨了。哈哈,開個玩笑~看了下覺得設計的挺有意思的,所以就謝了這篇文章。 簡單介紹一下,FreeSql 是NCC組織的沙盒級項目,是一款功能強大的 ORM 組件,支持 .NET Core ...
  • 0. 前言 這是一個新的系列,名字是《ASP.NET Core 入門到實戰》。這個系列主講ASP.NET Core MVC,輔助一些前端的基礎知識(能用來實現我們需要的即可,並非主講)。同時這個系列也會在後續介紹ASP.NET Core 平臺的其它類型的項目,並帶領大家以各個類型的項目為主要架構開發 ...
  • 我寫了一個Winform測試程式,用的System.Timers.Timer,在事件里,設置label1.Text,然後,居然句柄泄漏、用戶對象泄漏! 百思不得其解,最後換成System.Windows.Forms.Timer,居然不泄漏了! 最近睡眠不足,哪怕一個很小的問題,隨便搞搞,都半夜了! ...
  • leetcode-7. 整數反轉。 給出一個 32 位的有符號整數,你需要將這個整數中每位上的數字進行反轉。 示例 1: 輸入: 123 輸出: 321 示例 2: 輸入: -123 輸出: -321 示例 3: 輸入: 120 輸出: 21 註意: 假設環境只能存儲得下 32 位的有符號整數,則其 ...
  • 1. Java 虛擬機是什麼? 1.1 虛擬機 虛擬機:虛擬的電腦,一個用來執行虛擬電腦指令的軟體。 虛擬機分為系統虛擬機和程式虛擬機。 系統虛擬機:提供一個可運行完整操作系統的軟體平臺,如 Visual Box、VMware。 程式虛擬機:專門執行單個程式的,典型代表 Java 虛擬機。Jav ...
  • 前言 - strlen 概述 無意間掃到 glibc strlen.c 中代碼, 久久不能忘懷. 在一無所知的編程生涯中又記起點點滴滴: 編程可不是兒戲 ❀, 有些難, 也有些不捨. 隨軌跡一同重溫, 曾經最熟悉的 strlen 手感吧 ~ /* Copyright (C) 1991-2020 Fr ...
  • 背景 隊列[Queue]:是一種限定僅在表頭進行刪除操作,僅在表尾進行插入操作的線性表;即先進先出(FIFO-first in first out):最先插入的元素最先出來。 本文通過編碼實現鏈式隊列類,並模擬一個有趣的應用,能夠幫助我們對鏈式隊列有更深度的理解。 基本概念 結點 每個元素,除了存儲 ...