最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#中字符串優(yōu)化String.Intern、IsInterned詳解

 更新時間:2017年12月01日 10:38:18   作者:小匠頭  
這篇文章主要給大家介紹了關(guān)于C#中字符串優(yōu)化String.Intern、IsInterned的相關(guān)資料,文中通過示例代碼介紹的,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。

前言

string是一種很特殊的數(shù)據(jù)類型,它既是基元類型又是引用類型,在編譯以及運行時,.Net都對它做了一些優(yōu)化工作,正式這些優(yōu)化工作有時會迷惑編程人員,使string看起來難以琢磨。本文將給大家詳細介紹關(guān)于C#字符串優(yōu)化String.Intern、IsInterned的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細的介紹吧。

首先看一段程序:

using System;
 
class Program
{
 static void Main(string[] args)
 {
 string a = "hello world";
 string b = a;
 a = "hello";
 Console.WriteLine("{0}, {1}", a, b);
 Console.WriteLine(a == b);
 Console.WriteLine(object.ReferenceEquals(a, b));
 }
}

這個沒有什么特殊的地方,相信大家都知道運行結(jié)果:

hello, hello world
False
False

第二個WriteLine使用==比較兩個字符串,返回False是因為他們不一致。而最后一個WriteLine返回False,因為a、b的引用不一致。

接下來,我們在代碼的最后添加代碼:

Console.WriteLine((a + " world") == b);
Console.WriteLine(object.ReferenceEquals((a + " world"), b));

這個的輸出,相信也不會出乎大家的意料。前者返回True,因為==兩邊的內(nèi)容相等;后者為False,因為+運算符執(zhí)行完畢后,會創(chuàng)建一個新的string實例,這個實例與b的引用不一致。

上面這些就是對象的通常工作方式,兩個獨立的對象可以擁有同樣的內(nèi)容,但他們卻是不同的個體。

接下來,我們就來說一下string不尋常的地方

看一下下面這段代碼:

using System;

class Program
{
 static void Main(string[] args)
 {
 string hello = "hello";
 string helloWorld = "hello world";
 string helloWorld2 = hello + " world";
 
 Console.WriteLine("{0}, {1}: {2}, {3}", helloWorld, helloWorld2,
 helloWorld == helloWorld2,
 object.ReferenceEquals(helloWorld, helloWorld2));
 }
}

運行一下,結(jié)果為:

hello world, hello world: True, False

再一次,沒什么意外,==返回true因為他們內(nèi)容相同,ReferenceEquals返回False因為他們是不同的引用。
現(xiàn)在在后面添加這樣的代碼:

helloWorld2 = "hello world";
Console.WriteLine("{0}, {1}: {2}, {3}", helloWorld, helloWorld2,
 helloWorld == helloWorld2,
 object.ReferenceEquals(helloWorld, helloWorld2));

運行,結(jié)果為:

hello world, hello world: True, True

等一下,這里的hellowWorld與helloWorld2引用一致?這個結(jié)果,相信很多人都有些接受不了。這里的helloWorld2與上面的hello + " world"應(yīng)該是一樣的,但為什么ReferenceEquals返回的是True?

String.Intern

有經(jīng)驗的程序員們,應(yīng)該知道,一個大型項目中,字符串的數(shù)量是巨大的。有些時候會出現(xiàn)幾百、幾千、甚至幾萬的重復(fù)字符串存在。這些字符串的內(nèi)容相同,但卻會重復(fù)分配內(nèi)存,占用巨額的存儲空間,這個肯定是要優(yōu)化處理的。而C#在處理這個問題的時候,采用的就是普遍的做法,建立內(nèi)部的池,池中每一個不同的字符串存在唯一一個個體在池中(這個方案在各種大型項目中都能見得到)。而C#畢竟是一種語言,而不是一個面向某個具體領(lǐng)域的技術(shù),所以,它不能將這種內(nèi)部的池技術(shù),做成全部自動化的。因為我們不知道,將來C#會被使用到何種規(guī)模的項目中。如果完全自動化維護這個內(nèi)部池,可能會在大型項目中,造成內(nèi)存的巨大浪費,畢竟不是所有的字符串都有必要加到這個常駐的池中的。于是,C#提供了String.Intern和String.IsInterned接口,交給程序員自己維護內(nèi)部的池。

String.Intern的工作方式很好理解,你將一個字符串作為參數(shù)使用這個接口,如果這個字符串已經(jīng)存在池中,就返回這個存在的引用;如果不存在就將它加入到池中,并返回引用,例如:

Console.WriteLine(object.ReferenceEquals(String.Intern(helloWorld), String.Intern(helloWorld2)));

這段代碼將返回True,盡管helloWorld與helloWorld2的引用不同,但他們的內(nèi)容相同。

這里我們花幾分鐘,測試一下String.Intern,因為在某些情況下,它產(chǎn)生的結(jié)果,有點違反直覺。這里是一個例子:

string a = new string(new char[] {'a', 'b', 'c'});
object o = String.Copy(a);
Console.WriteLine(object.ReferenceEquals(o, a));
String.Intern(o.ToString());
Console.WriteLine(object.ReferenceEquals(o, String.Intern(a)));

第一個WriteLine返回False很好理解,因為String.Copy創(chuàng)建了一個a的新的實例,所以,o與a的引用不用。

但為什么第二個WriteLine返回的是True?思考一下吧,下面再看一個例子:

object o2 = String.Copy(a);
String.Intern(o2.ToString());
Console.WriteLine(object.ReferenceEquals(o2, String.Intern(a)));

這個看起來,與上面的做了同樣的事,但為什么WriteLine返回的是False?

首先,需要說明一下ToString的工作方式,它總是返回它自身的引用。o是一個指向“abc”的變量,調(diào)用ToString返回的就是這個引用。所以,對于上面的內(nèi)容,可以這樣解釋:

  • 開始,變量a指向字符串對象“abc”(#1),變量o指向另一個字符串對象(#2),也包含“abc”。
  • 調(diào)用String.Intern(o.ToString())將對象#2的引用添加到內(nèi)部池中。
  • 現(xiàn)在#2對象已經(jīng)存在池中了,任何時候,使用“abc”調(diào)用String.Intern都將返回#2的引用(o指向了這個對象)。
  • 所以,當你使用ReferenceEquals比較o和String.Intern(a)時,返回True。因為String.Intern(a)返回的是#2的引用。
  • 現(xiàn)在我們創(chuàng)建一個新的變量o2,使用String.Copy(a)創(chuàng)建一個新的對象#3,它也包含“abc”。
  • 調(diào)用String.Intern(o2.ToString())沒有向內(nèi)部池中添加任何內(nèi)容,因為“abc”已經(jīng)存在(#2)。
  • 所以,此時調(diào)用Intern返回的是對象#2的引用。注意,這里并沒有使用類似o2 = String.Intern(o2.ToString())這樣的代碼。
  • 這就是為什么最后一行WriteLine打印的False的原因,因為我們在嘗試比較#3與#2的引用。如果如7中所說,添加o2 = String.Intern(o2.ToString())這樣的代碼,WriteLine返回的就是True。

String.IsInterned

IsInterned,正如它的名字,判斷一個字符串是不是已經(jīng)在內(nèi)部池中。如果傳入的字符串已經(jīng)在池中,則返回這個字符串對象的引用,如果不再池中,返回null。

下面是一個IsInterned例子:

string s = new string(new char[] {'x', 'y', 'z'});
Console.WriteLine(String.IsInterned(s) ?? "not interned");
String.Intern(s);
Console.WriteLine(String.IsInterned(s) ?? "not interned");
Console.WriteLine(object.ReferenceEquals(
String.IsInterned(new string(new char[] { 'x', 'y', 'z' })), s));

第一個WriteLine打印的是“not interned”,因為“xyz”還沒有存在于內(nèi)部池中;第二個WriteLine打印了“xyz”因為現(xiàn)在內(nèi)部池中有了“xyz”;第三個WriteLine打印True,因為對象引用的就是內(nèi)部池中的“xyz”。

常量字符串自動被加入內(nèi)部池

改變最后一行代碼為:

Console.WriteLine(object.ReferenceEquals("xyz", s));

你會發(fā)現(xiàn),奇怪的事情發(fā)生了,這些代碼不再輸出“not interned”了,并且最后的兩個WriteLine輸出的是False!發(fā)生了什么?

原因就是這個最后添加的那行代碼中的常量“xyz”,CLR會將程序中使用的字符常量自動添加到內(nèi)部池中。所以,當最后一行被添加之后,“xyz”在程序“運行之前”(避免嚴謹,這里用引號)就已經(jīng)存在于內(nèi)部池中。所以,當調(diào)用String.IsInterned的時候,返回的不再是null,而是指向“xyz”的引用。這也解釋了,為什么后面的ReferenceEquals返回False,因為s從來沒有被加到內(nèi)部池中,其指向也不是內(nèi)部池的"xyz"。

編譯器比你想象的要聰明

改變最后一行代碼為:

Console.WriteLine(object.ReferenceEquals("x" + "y" + "z", s));

運行一下,你會發(fā)現(xiàn)運行結(jié)果和直接使用“xyz”一樣。但這里使用了+運算符???編譯器不應(yīng)該知道”x“+"y"+"z"最終的結(jié)果吧?

實際上,如果你將”x“+"y"+"z"替換為String.Format("{0}{1}{2}",'x','y','z'),結(jié)果確實就不一樣了。某種原因,CLR會將使用+運算符鏈接的字符串視為常量,而String.Format卻需要在運行時才能知道結(jié)果。為什么?看一下下面的代碼:

using System;
 
class Program {
 public static void Main() {
 Console.WriteLine("x" + "y" + "z");
 }
}

這段代碼編譯之后,使用Ildasm.exe查看,會看到:


Screenshot - ILDasm intern-xyz Main method.png

看到了吧,編譯器足夠聰明,將”x“+"y"+"z"替換為”xyz“。

總結(jié)

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

相關(guān)文章

  • C#簡單讀取、改變文件的創(chuàng)建、修改及訪問時間的方法

    C#簡單讀取、改變文件的創(chuàng)建、修改及訪問時間的方法

    這篇文章主要介紹了C#簡單讀取、改變文件的創(chuàng)建、修改及訪問時間的方法,涉及C#文件類SetCreationTime、SetLastWriteTime及SetLastAccessTime的相關(guān)使用技巧,需要的朋友可以參考下
    2015-07-07
  • C#無限參數(shù)的寫法

    C#無限參數(shù)的寫法

    這篇文章主要介紹了C#無限參數(shù)的寫法,通過循環(huán)遍歷再結(jié)合paras.Add方法實現(xiàn)無限參數(shù)的功能,是比較實用的技巧,需要的朋友可以參考下
    2014-12-12
  • c#禁止通過拖動,雙擊標題欄改變窗體大小的方法

    c#禁止通過拖動,雙擊標題欄改變窗體大小的方法

    今天小編就為大家分享一篇c#禁止通過拖動,雙擊標題欄改變窗體大小的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • C#中利用斷點操作調(diào)試程序的步驟詳解

    C#中利用斷點操作調(diào)試程序的步驟詳解

    所謂斷點調(diào)試就是檢測執(zhí)行路徑和數(shù)據(jù)是否正確,中斷游戲運行在線調(diào)試,下面這篇文章主要給大家介紹了關(guān)于C#中利用斷點操作調(diào)試程序的相關(guān)資料,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • C#索引屬性用法實例分析

    C#索引屬性用法實例分析

    這篇文章主要介紹了C#索引屬性用法,實例分析了C#聲明索引屬性的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • c#操作附加數(shù)據(jù)庫的方法

    c#操作附加數(shù)據(jù)庫的方法

    這篇文章主要介紹了c#操作附加數(shù)據(jù)庫的方法,涉及C#針對附加數(shù)據(jù)庫的相關(guān)操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-08-08
  • C#中日期時間的簡單操作

    C#中日期時間的簡單操作

    這篇文章介紹了C#中日期時間的簡單操作,有需要的朋友可以參考一下
    2013-08-08
  • C#提取網(wǎng)頁中超鏈接link和text部分的方法

    C#提取網(wǎng)頁中超鏈接link和text部分的方法

    這篇文章主要介紹了C#提取網(wǎng)頁中超鏈接link和text部分的方法,涉及C#正則表達式及字符串操作相關(guān)技巧,需要的朋友可以參考下
    2016-02-02
  • C#實現(xiàn)對文件進行加密解密的方法

    C#實現(xiàn)對文件進行加密解密的方法

    這篇文章主要介紹了C#實現(xiàn)對文件進行加密解密的方法,涉及C#加密與解密的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-04-04
  • .NET利用C#字節(jié)流動態(tài)操作Excel文件

    .NET利用C#字節(jié)流動態(tài)操作Excel文件

    在.NET開發(fā)中,通過字節(jié)流動態(tài)操作Excel文件提供了一種高效且靈活的方式處理數(shù)據(jù),本文將演示如何在.NET平臺使用C#通過字節(jié)流創(chuàng)建,讀取,編輯及保存Excel文件,需要的可以參考下
    2024-12-12

最新評論

大洼县| 鹤岗市| 仁化县| 荆州市| 德清县| 衡水市| 桑日县| 永川市| 仁寿县| 安陆市| 藁城市| 亚东县| 高安市| 福安市| 中江县| 山阴县| 太原市| 花垣县| 呼和浩特市| 梁河县| 古田县| 衡阳市| 体育| 黎川县| 贞丰县| 积石山| 林甸县| 襄樊市| 桑植县| 施秉县| 乡城县| 普安县| 隆安县| 浦北县| 都昌县| 利辛县| 长葛市| 陆河县| 九寨沟县| 临桂县| 安徽省|