国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

引用類型和值類型

Original 2016-11-09 14:58:45 563
abstract:CLR支持兩種類型:引用類型和值類型。雖然FCL的大多數(shù)類型都是引用類型,但程序員用的最多的還是引用類型,引用類型總是從托管堆分配,c#的new操作符返回對象內(nèi)存地址-即指向?qū)ο髷?shù)據(jù)的內(nèi)存地址。使用引用類型必須注意性能問題。首先要認(rèn)清楚以下4個(gè)方面:1、內(nèi)存必須從托管堆分配。2、堆上分配的每個(gè)對象都有一些額外的成員,這些成員必須初始化。3、對象中的其它字節(jié)(為字段而設(shè))總是設(shè)為零。4、從托管堆分配

CLR支持兩種類型:引用類型和值類型。雖然FCL的大多數(shù)類型都是引用類型,但程序員用的最多的還是引用類型,引用類型總是從托管堆分配,c#的new操作符返回對象內(nèi)存地址-即指向?qū)ο髷?shù)據(jù)的內(nèi)存地址。使用引用類型必須注意性能問題。首先要認(rèn)清楚以下4個(gè)方面:

1、內(nèi)存必須從托管堆分配。

2、堆上分配的每個(gè)對象都有一些額外的成員,這些成員必須初始化。

3、對象中的其它字節(jié)(為字段而設(shè))總是設(shè)為零。

4、從托管堆分配對象時(shí),可能強(qiáng)制執(zhí)行一次垃圾回收。

  如果所有類型都是引用類型,應(yīng)用程序的性能將會顯著下降。設(shè)想每次使用Int32值時(shí)都進(jìn)行一次內(nèi)存分配,性能會受到多么大的影響,為了提升簡單和常用的類型的性能,CLR提供了名為‘值類型’的輕量級類型,值類型的實(shí)例一般在線程棧上分配,在代表值類型實(shí)例的變量中不包含指向?qū)嵗闹羔?。相反,變量中包含了?shí)例本身的字段。由于變量已經(jīng)包含了實(shí)例的字段。因此,值類型的使用緩解了托管堆的壓力,并減少了應(yīng)用程序生存期內(nèi)的垃圾回收次數(shù)。

  文檔清楚指出哪些是值類型,哪些是引用類型。在文檔中查看類型時(shí),任何成為‘類’的類型都是引用類型。例如:System.Exception類,System.IO.FileStream類以及System.Random類都是引用類型。相反所有的值類型都成為結(jié)構(gòu)或枚舉。例如:System.Int32結(jié)構(gòu)、System.Boolean結(jié)構(gòu)、System.Decimal結(jié)構(gòu)、System.TimeSpan結(jié)構(gòu)、System.DayOfWeek枚舉等等。

  進(jìn)一步研究文檔,會發(fā)現(xiàn)所有的結(jié)構(gòu)都是抽象類型System.ValueType的直接派生類。System.ValueType本身又直接從System.Object派生。根據(jù)定義,所有值類型都必須從System.ValueType派生。CLR和所有編程語言都給予枚舉特殊待遇。

  雖然不能在定義值類型時(shí)為他選擇基類型,但如果愿意,值類型可以實(shí)現(xiàn)一個(gè)或多個(gè)接口。除此之外,所有值類型都隱式密封,目的是防止將值類型用作其他引用類型或這類型的基類。例如:無法將Boolean、Char、Int32、Uint64、Single、Double、Decimal等類型來定義任何新類型。

  以下代碼演示了引用類型和值類型的區(qū)別:

//引用類型(因?yàn)槭莄lass)
class SomeRef
{
     public Int32 x;
}
 
//值類型(因?yàn)槭莝truct)
struct SomeVal
{
    public Int32 x;
}
 
static void ValueTypeDemo()
{
     SomeRef r1=new SomeRef();                 //往堆上分配
     SomeVal v1 = new SomeVal();               //往棧上分配
      
     r1.x = 5;                                                //提領(lǐng)指針
     v1.x = 5;                                               //在棧上修改
     Console.WriteLine(r1.x);                         //顯示為5
     Console.WriteLine(v1.x);                        //同樣顯示為5
      
     SomeRef r2 = r1;                                 //只復(fù)用指針(引用)
     SomeVal v2 = v1;                                //在棧上分配并復(fù)制成員
     r1.x = 8;                                             //r1.x和r2.x都會修改成新值
     v1.x=9;                                              //v1.x會修改,v2.x不會修改
     
     Console.WriteLine(r1.x);                      //顯示8
     Console.WriteLine(r2.x);                      //顯示8
     Console.WriteLine(v1.x);                     //顯示9
     Console.WriteLine(v2.x);                     //顯示5
}

 上述代碼中,SomeVal用struct聲明,而不是用更常用的class。在C#中,常用struct聲明的類型是值類型,用class聲明的類型是引用類型。可以看出引用類型和值類型的區(qū)別相當(dāng)大。再代碼中使用類型時(shí),必須注意是值類型還是引用類型,因?yàn)檫@會極大的影響在代碼中表達(dá)自己意圖的方式。

  上述代碼中有這樣一行:

SomeVal v1 = new SomeVal();               //往棧上分配

 因?yàn)檫@行代碼的寫法,似乎要在托管堆上分配一個(gè)SomeVal的實(shí)例。但c#編譯器知道SomeVal是值類型,所以會生成正確的IL代碼,在線程棧上分配一個(gè)SomeVal的實(shí)例。c#還會確保值類型中所有的字段都初始化為零。

SomeVal v1;   //在棧上分配空間

這一行生成的IL代碼也會在線程棧上分配實(shí)例,并將字段初始化為零。唯一的區(qū)別在于,如果使用new操作符,C#會認(rèn)為實(shí)例已經(jīng)初始化,以下代碼更清楚的進(jìn)行了說明:

//這兩行代碼都能夠編譯通過,因?yàn)閏#認(rèn)為v1的字段已經(jīng)初始化為0
SomeVal v1 = new SomeVal();
Int32 a= v1.x;
 
//這兩行代碼不能夠編譯通過,因?yàn)閏#不認(rèn)為v1的字段已經(jīng)初始化為0
SomeVal v1;
Int32 a= v1.x;  //error cs0170: 使用了可能未賦值的字段“x”;

設(shè)計(jì)自己的類型時(shí),要仔細(xì)考慮清楚是否應(yīng)該定義成值類型還是引用類型。值類型有時(shí)候能提供更好的性能。具體的說,除非滿足一下全部條件,否則不應(yīng)該聲明為值類型。

1、類型具有基元類型的行為。也就是說是十分簡單的類型,沒有成員會修改類型的任何實(shí)例字段。

2、類型不需要從其他任何類型繼承。

3、類型也不派生出其它任何類型。


Release Notes

Popular Entries