欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c#基礎(chǔ)系列之System.String的深入理解

 更新時(shí)間:2018年09月16日 11:47:14   作者:大菜  
這篇文章主要給大家介紹了關(guān)于c#基礎(chǔ)系列之System.String的深入理解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

幾乎任何一個(gè)項(xiàng)目都離不開(kāi)對(duì)字符串的處理,在C和C++編程中,許多程序的漏洞都是由于字符串緩沖區(qū)溢出造成的。為了避免在C#中出現(xiàn)類似的問(wèn)題,同時(shí)也為了使用更方便,C#中專門(mén)設(shè)置了兩個(gè)字符串處理類:String類和StringBuilder類。

本文主要給大家介紹了關(guān)于c#基礎(chǔ)系列之string的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧

擴(kuò)展閱讀:深入理解值類型和引用類型

基本概念

string(嚴(yán)格來(lái)說(shuō)應(yīng)該是System.String) 類型是我們?nèi)粘oding中用的最多的類型之一。那什么是String呢?^ ~ ^

String是一個(gè)不可變的連續(xù)16位的Unicode代碼值的集合,它直接派生自System.Object類型。

與之對(duì)應(yīng)的還有一個(gè)不常用的安全字符串類型System.Security.SecureString,它會(huì)在非托管的內(nèi)存上分配,以便避開(kāi)GC的黑手。主要用于安全性特高的場(chǎng)景。[具體可查看msdn這里不展開(kāi)討論了。=>msdn查看詳情

特性

  • 由于String類型直接派生于Object,所以它是引用類型,那就意味著String對(duì)象的實(shí)例總是存在于堆上。
  • String具有不變性,也就是說(shuō)一旦初始化,它的值將永遠(yuǎn)不變。
  • String類型是封閉的,換言之,你的任何類型不能繼承String。
  • 定義字符串實(shí)例的關(guān)鍵字string只是System.String 類型的一個(gè)映射。


注意事項(xiàng)

  • 關(guān)于字符串中的回車符和換行符一般大家喜歡直接硬編碼‘\r\n',但是不建議這么做,一旦程序遷移到其他平臺(tái),將出現(xiàn)錯(cuò)誤。相反,推薦使用System.Environment類的NewLine屬性來(lái)生成回車符和換行符,可以跨平臺(tái)使用的。
  • 常量字符串的拼接和非常量字符串在CLR中行為是不一樣的。具體請(qǐng)查看性能部分。
  • 字符串之前加@符號(hào)會(huì)改變編譯器的行為,如果加了@符號(hào),編譯器會(huì)把String中的轉(zhuǎn)義字符視為正常字符來(lái)顯示。也就是我定義的什么內(nèi)容就是什么內(nèi)容,主要在使用文件路徑或者目錄字符串中使用。以下兩個(gè)String內(nèi)容的輸出將完全一致。
  static void Main(string[] args)
   {
    string a = "c:\\temp\\1";
    string b = @"c:\temp\1";
    Console.WriteLine(a);
    Console.WriteLine(b);
    Console.Read();   
   } 

性能

  • c#的編譯器直接支持String類型,并將定義的常量字符串在編譯期直接存放到模塊的元數(shù)據(jù)中。然后會(huì)在運(yùn)行時(shí)直接加載。這也說(shuō)明String類型的常量在運(yùn)行時(shí)是有特殊待遇的。
  • 由于字符串的不變性,也就意味著多個(gè)線程同時(shí)操作該字符串不會(huì)有任何線程安全的問(wèn)題。這在某些共享配置的設(shè)計(jì)中很有用。
  • 如果程序經(jīng)常會(huì)對(duì)比重復(fù)度比較高的字符串,這會(huì)造成性能上的影響,因?yàn)閷?duì)比字符串是要經(jīng)過(guò)幾個(gè)步驟的。為此CLR引入了一個(gè)字符串重用的技術(shù),學(xué)名叫做‘字符串留用'。原理就是:CLR會(huì)在初始化的時(shí)候創(chuàng)建一個(gè)內(nèi)部的哈希表,key是字符串,value就是留用字符串在托管堆上的引用。
    String類型提供了兩個(gè)靜態(tài)方法來(lái)操作這個(gè)哈希表:

String.Intern

String.IsInterned

具體請(qǐng)查看msdn(https://msdn.microsoft.com/zh-cn/library/system.string.isinterned(v=vs.110).aspx)

但是c#編譯器默認(rèn)是不開(kāi)啟字符串留用功能的,因?yàn)槿绻绦虼罅堪炎址粲?,?yīng)用程序總體性能可能會(huì)變得更慢。(微軟也是挺糾結(jié)的,程序員TMD的更糾結(jié))

如果我們的程序中有很多個(gè)一模一樣值的常量字符串, c#的編譯器會(huì)在編譯期間把這些字符串合并為一個(gè)并寫(xiě)入模塊的元數(shù)據(jù)中,然后修改所有引用該字符串的代碼。這也是一種字符串重用技術(shù),學(xué)名‘字符串池'。這意味著什么呢?這意味著所有值相同的常量字符串其實(shí)引用的是同一個(gè)內(nèi)存地址的實(shí)例,在相同值非常多的情況下能顯著提高性能和節(jié)省大量?jī)?nèi)存。

string s1 = "hello 大菜";
string s2 = "hello 大菜";
unsafe
{
 fixed (char* p = s1)
 {
  Console.WriteLine("字符串地址= 0x{0:x}", (int)p);

 }
 fixed (char* p = s2)
 {
  Console.WriteLine("字符串地址= 0x{0:x}", (int)p);

 }
} 

輸出結(jié)果:

字符串地址= 0x80002d84
字符串地址= 0x80002d84

可見(jiàn)實(shí)例的值只分配了一次,但是有一點(diǎn)需要說(shuō)明,字符串僅用于編譯期能確定值的字符串,也就是常量字符串。如果我的程序修改為:

args = new string[] { "dfasfdsa"};
string s1 = "hello 大菜"+ args[0];
string s2 = "hello 大菜"+args[0];
unsafe
{
 fixed (char* p = s1)
 {
  Console.WriteLine("字符串地址= 0x{0:x}", (int)p);

 }
 fixed (char* p = s2)
 {
  Console.WriteLine("字符串地址= 0x{0:x}", (int)p);

 }
}

運(yùn)行結(jié)果:

字符串地址= 0x2e3c
字符串地址= 0x2e7c

平時(shí)coding避免不了字符串的連接,如果一個(gè)頻繁拼接字符串的場(chǎng)景下使用‘+',對(duì)程序整體性能和GC影響還是挺大的,為此c#推出了 StringBuilder類型來(lái)優(yōu)化字符串的拼接。相對(duì)于String類型的不變性來(lái)說(shuō),StringBuilder更像是可變的字符串類型。它的底層數(shù)據(jù)結(jié)構(gòu)是一個(gè)Char的數(shù)組。另外還有容量(默認(rèn)為16),最大容量(默認(rèn)為int.MaxValue)等屬性。StringBuilder的優(yōu)勢(shì)在于字符總數(shù)未超過(guò)‘容量'的時(shí)候,底層數(shù)組不會(huì)重新分配,這和String每次都重新分配形成最大的對(duì)比。如果字符總數(shù)超過(guò)‘容量',StringBuilder會(huì)自動(dòng)倍增容量屬性,用一個(gè)新的數(shù)組來(lái)容納原來(lái)的值,原來(lái)數(shù)組將會(huì)被GC回收??梢?jiàn)如果StringBuilder頻繁的動(dòng)態(tài)擴(kuò)容也會(huì)損害性能,但是影響可能會(huì)比String小的多。 合理的設(shè)置StringBuilder初始容量對(duì)程序有很大幫助。測(cè)試如下:

int count = 100000;
Stopwatch sw = new Stopwatch();
sw.Start();
string s = "";
for (int i = 0; i < count; i++)
 {
  s += i.ToString();
 }
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

運(yùn)行結(jié)果:

14221

查看GC的情況

Gc執(zhí)行的是如此頻繁。 性能是可想而知的。接著看一下StringBuilder

int count = 100000;
Stopwatch sw = new Stopwatch();
sw.Start();   
StringBuilder sb = new StringBuilder();//聽(tīng)說(shuō)程序員都這樣命名StringBuilder
for (int i = 0; i < count; i++)
 {
 sb.Append(i.ToString());
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

運(yùn)行結(jié)果:

12

GC情況:


幾乎沒(méi)有GC(可能還未達(dá)到觸發(fā)GC的臨界點(diǎn)),如果我合理初始化了StringBuilder 容量,生產(chǎn)環(huán)境中結(jié)果差距將會(huì)更大。 呵呵 ^ ~ ^

其他

關(guān)于字符串留用和字符串池

一個(gè)程序集加載的時(shí)候,CLR默認(rèn)會(huì)留用該程序集元數(shù)據(jù)中描述的所有文本常量字符串。由于可能會(huì)出現(xiàn)額外的哈希表查找造成的性能下降的現(xiàn)象,所以現(xiàn)在可以禁用這個(gè)特性了。

coding中我們平常比較兩個(gè)字符串是否相等,那這個(gè)過(guò)程是怎么樣的呢?

  • 首先判斷字符的數(shù)量是否相等。
  • CLR逐個(gè)對(duì)比字符最終確定是否相等。

這個(gè)場(chǎng)景是適合字符串留用的。因?yàn)椴辉傩枰?jīng)過(guò)以上的兩個(gè)步驟,直接哈希表拿到value就可以對(duì)比確定了。

關(guān)于字符串拼接性能

基于以上所有知識(shí),那是不是StringBuilder拼接字符串性能永遠(yuǎn)都高于符號(hào)‘+'呢?答案是否定的。

 static void Main(string[] args)
  {
   int count = 10000000;
   Stopwatch sw = new Stopwatch();
   sw.Start();   
   string str1 = "str1", str2 = "str2", str3 = "str3";
   for (int i = 0; i < count; i++)
   {
    string s = str1 + str2 + str3;
   }
   sw.Stop();
   Console.WriteLine($@"+用時(shí): {sw.ElapsedMilliseconds}" );

   sw.Reset();
   sw.Start();
   for (int i = 0; i < count; i++)
   {
    StringBuilder sb = new StringBuilder();//聽(tīng)說(shuō)程序員都這樣命名StringBuilder
    sb.Append(str1).Append(str2).Append(str3);
   }
   sw.Stop();
   Console.WriteLine($@"StringBuilder.Append 用時(shí): {sw.ElapsedMilliseconds}");

   Console.Read();
  }

運(yùn)行結(jié)果:

+用時(shí): 553
StringBuilder.Append 用時(shí): 975

符號(hào)‘+'最終會(huì)調(diào)用String.Concat方法,當(dāng)同時(shí)連接幾個(gè)字符串時(shí),并不是每連接一個(gè)都分配一次內(nèi)存,而是把幾個(gè)字符都作為 String.Concat方法的參數(shù),只分配一次內(nèi)存。所以在拼接的字符串個(gè)數(shù)比較少的場(chǎng)景下,String.Concat 性能是略高于StringBuilder.Append。string.Format 方法最終調(diào)用的是StringBuilder,這里不做展開(kāi)討論了,請(qǐng)自行參考其他文檔。

所以萬(wàn)事都不是絕對(duì)的?。∶總€(gè)事物都有適合自己的場(chǎng)景,我們都需要自己去探索。(程序員太累了)

以上都是非生產(chǎn)環(huán)境測(cè)試結(jié)果,如果錯(cuò)誤,請(qǐng)及時(shí)指正

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • 解決C# winForm自定義鼠標(biāo)樣式的兩種實(shí)現(xiàn)方法詳解

    解決C# winForm自定義鼠標(biāo)樣式的兩種實(shí)現(xiàn)方法詳解

    本篇文章是對(duì)在C#中winForm自定義鼠標(biāo)樣式的兩種實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • c# 設(shè)置TeeChart控件的提示文本

    c# 設(shè)置TeeChart控件的提示文本

    這篇文章主要介紹了c# 如何設(shè)置TeeChart控件的提示文本,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2020-11-11
  • c# WPF中System.Windows.Interactivity的使用

    c# WPF中System.Windows.Interactivity的使用

    這篇文章主要介紹了c# WPF中System.Windows.Interactivity的使用,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • C# ThreadPool之QueueUserWorkItem使用案例詳解

    C# ThreadPool之QueueUserWorkItem使用案例詳解

    這篇文章主要介紹了C# ThreadPool之QueueUserWorkItem使用案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C# 鼠標(biāo)穿透窗體功能的實(shí)現(xiàn)方法

    C# 鼠標(biāo)穿透窗體功能的實(shí)現(xiàn)方法

    通過(guò)以下代碼,在窗體啟動(dòng)后調(diào)用方法SetPenetrate() 即可實(shí)現(xiàn)窗體的穿透功能,有需要的朋友可以參考一下
    2013-10-10
  • C#調(diào)用百度翻譯實(shí)現(xiàn)翻譯HALCON的示例

    C#調(diào)用百度翻譯實(shí)現(xiàn)翻譯HALCON的示例

    HALCON示例程序的描述部分一直是英文的,看起來(lái)很不方便。本文就使用百度翻譯實(shí)現(xiàn)翻譯HALCON,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C#定位txt指定行的方法小例子

    C#定位txt指定行的方法小例子

    近日,在開(kāi)發(fā)CAD插件時(shí)需要定位TXT文件指定行并將其選中,在網(wǎng)絡(luò)找了一下沒(méi)有找到現(xiàn)成的,自己編了一個(gè)定位程序,實(shí)現(xiàn)了定位功能..與大家分享
    2013-04-04
  • C#生成帶二維碼的專屬微信公眾號(hào)推廣海報(bào)實(shí)例代碼

    C#生成帶二維碼的專屬微信公眾號(hào)推廣海報(bào)實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于利用C#如何生成帶二維碼的專屬微信公眾號(hào)推廣海報(bào)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們一起來(lái)看看吧
    2018-12-12
  • C#操作DataTable的實(shí)現(xiàn)步驟

    C#操作DataTable的實(shí)現(xiàn)步驟

    本文主要介紹了C#操作DataTable的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • KMP算法的C#實(shí)現(xiàn)方法

    KMP算法的C#實(shí)現(xiàn)方法

    這篇文章主要介紹了KMP算法的C#實(shí)現(xiàn)方法,代碼簡(jiǎn)潔實(shí)用,需要的朋友可以參考下
    2014-09-09

最新評(píng)論