本來寫了蠻多的,結果因為重啟了一下機器導致寫的東西都沒了。
然後再回想之前寫了什麼,反而更像是把知識提煉了一番。
關於字符
字符什麼的只要記住.net裡面都用的Unicode編碼就好。字符和數字之間轉換用強制轉換是最簡單且高效的,
字符串是引用類型,存在與堆上,然而同一般的對象用newobj這個IL指令創建不同,字符串由ldstr指令創建。(load string)
關於字符串
字符串是不可變的,所有的String的方法都是創建一個新的字符串。
用+號去拼接字符串,會在堆上創建多個string對象,而堆上的對象考慮到垃圾回收就會影響性能,所以建議用StringBuilder去拼接。
字符串比較
雖然String提供了一堆比較方法,並且《CLR via C#》這本書的作者也推薦用這些比較,因為==和!=這種比較方式調用者並沒有顯式指出用什麼規則來比較,而如果顯示地指出以什麼規則來比較,代碼容易閱讀和維護。
var str1 = "字符串1"; var str2 = "字符串2"; bool result1= str1.Equals(str2, StringComparison.OrdinalIgnoreCase);//使用序號排列(就是說對本地語言文化不敏感),並忽略大小寫來比較。 bool result2 = str1 == str2;//常用的比較
然而,於我而言,確實是==更加明了,這個就看個人了。這些用方法比較的時候確實在有些多語言文化的場景比較好用,然而對於一般場景,我個人認為==更好一點,起碼我自己看起來更好閱讀和理解。
以StringComparison.Ordinal規則比較的話,CLR會快速先比較字符數量,數量相同才繼續比較單獨字符。而如果執行語言文化敏感的話,即使數量不同也有可能相等,所以一開始就會比較單個字符,這樣就很耗性能。
System.StringComparer類也能執行字符串比較,它適用於大量不同字符串反復執行同一種比較。
字符串留用
CLR可通過一個String對象共享多個完全一致的String內容,這樣就減少了字符串數量,節省內存,這就是字符串留用。
在.NET 4.5中自然會在程序集加載時對代碼中的字面量字符串進行字符串留用,然而之前的版本就需要手動了。
String.Intern方法就是字符串留用的方法,將字符串加入一個哈希表中,如果哈希表中有就不加入,沒有就加入。
這樣當然可以減少內存,因為以後只引用一個字符串對象。但是要明白留存字符串這個操作也是需要消耗性能的。所以具體情況具體分析,還是需要慎重使用字符串留存。
字符串池
對於所有的字面量字符串中,相同內容的字符串,實際上都是引用的字符串池中的一個字符串。這是在C#編譯器編譯的時候就已經弄好的。
高效率構造字符串——StringBuilder
StringBuilder從字面意義上就很好理解了,字符串拼接什麼的就用它好了。可以認為裡面就是一個字符數組。
然而要理解StringBuilder的以下概念
一般用用Append和AppendFormat進行追加字符串,當然也有其它的操作,只要明白裡面操作的是一個數組就好。
雖然本書還介紹了一些字符串格式化和解析字符串的方式,然而
字符串編碼——字符和字節的相互轉換
對於使用漢字的我們使用字符串的話用Unicode沒什麼影響,因為漢字就占兩個字節,然而對於英文字符實際上僅僅用一個字節就夠了,但是在Unicode中還是會占兩個字節,其中一個字節用於表示這個英文字符,另一個字節干脆就是\0。
所以一些英文翻譯啊什麼的,或者一大段英文文章的傳送,那麼將這些Unicode字符串編碼成壓縮的字節數組傳送起來更有效率。
通常也就是用System.IO.BinaryWriter或者System.IO.StreamWriter時,需要進行編碼,相應的讀取時也需要解碼。
一般不指定一種編碼方案,那麼就默認為UTF-8。(可以簡單理解為中文兩個字節,英文一個字節)
還有一種常用編碼方案是UTF-16,也就是中英文都是兩個字節,也被稱為Unicode編碼。(對於漢字而言,其實用UTF-16編碼,比UTF-8更快)
其它的編碼方式就不說了,對於我們而言基本上都是坑。
當我們進行編碼時盡量用Encoding.Unicode獲取編碼方案構造對象,而不是用System.Text.UnicodeEncoding這種。
因為前者如果之前有請求會直接返回上次請求的對象給你,不會為每個請求構造新的對象。
而後者每次都會在托管堆中創建新的對象,所以會對性能有所影響。然而在System.Text中的這些派生自Encoding的編碼類有特殊的構造器可以在對無效序列解碼時拋出異常,所以如果要保證安全性,防范無效輸入那麼用後面這種比較好。
獲取了這些編碼方案構造對象後就可以利用GetBytes和GetString來將字符串轉換為字節數組和將字節數組轉換為字符串。
字節流的編碼
就是通過System.Net.Sockets.NetworkStream對象讀取一個UTF-16編碼字符串,因為這種字節流通常以數據塊形式傳輸,而如果一次從流中讀取5個字節,而不是2的倍數的字節數,那麼就可能會造成數據損壞。
所以可以用Encoding.Unicode.GetDecoder()獲取一個新的構造對象,這個對象含有GetChars和GetCharCount兩個方法。調用GetChars時它會盡可能多的解碼,如果解碼數組的字節不足以完成一個字符時,那麼剩余的字符會保存到這個Decoder內部,下次調用它時,此Decoder會利用之前剩余的字節,再加上傳給它的字節數組來進行解碼。從流中讀取Decoder對象的作用很大。
相反的編碼一樣。
以下為簡單的Decoder解碼示例
string strTroy = "奇葩"; Byte[] bytesTroy = Encoding.Unicode.GetBytes(strTroy);//形成長度為4的字節數組 Byte[] b1 = { bytesTroy[0], bytesTroy[1], bytesTroy[2] };//一個奇,半個葩 Byte[] b2 = { bytesTroy[3] };//半個葩 //以上操作算是模擬了按數據塊獲取,接下來 var decoder = Encoding.Unicode.GetDecoder(); char[] result=new char[10];//解碼後的字符數組 var charindex = decoder.GetCharCount(b1, 0, b1.Length);//若解碼b1能形成的字符個數 decoder.GetChars(b1,0, b1.Length, result, 0, false);//第一個0為從b1第0個位置開始解碼,第二個0是從result的第0個位置開始寫入 decoder.GetChars(b2,0, b2.Length, result, charindex, false); Console.WriteLine(string.Join("",result));//奇葩
安全字符串
System.Security.SecureString類,就是一個更安全的字符串類。
構造這個類的對象後,會在內部分配一個非托管內存塊,以避開垃圾回收器。
和String對象不同,SecureString對象在回收後加密字符串的內容將不再存在於內存中。
當然這樣的字符串如果不是信用卡啊密碼什麼的就不需要,畢竟會有性能影響。