c 引用型別與值型別的區別詳解 轉)

2021-07-03 13:31:57 字數 4433 閱讀 1962

本篇文章是對c#中引用型別與值型別的區別進行了詳細的分析介紹,需要的朋友參考下

解析:clr支援兩種型別:值型別和引用型別。用jeffrey richter(《clr via c#》作者)的話來說,「不理解引用型別和值型別區別的程式設計師將會把**引入詭異的陷阱和諸多效能問題」。這就要求我們正確理解和使用值型別和引用型別。

值型別包括c#的基本型別(用關鍵字int、char、float等來宣告),結構(用struct關鍵字宣告的型別),列舉(用enum關鍵字宣告的型別);而引用型別包括類(用class關鍵字宣告的型別)和委託(用delegate關鍵字宣告的特殊類)。

(1)在c#中,變數是值還是引用僅取決於其基本資料型別。

c#的基本資料型別都與平台無關。c#的預定義型別並沒有內置於語言中,而是內置於.net framework中。.net使用通用型別系統(cts)定義可以在中間語言(il)中使用的預定義資料型別。c#中所有的資料型別都是物件。它們可以有方法、屬性等。例如,在c#中宣告乙個int變數時,宣告實際上是cts(通用型別系統)中system.int32的乙個例項:

複製**

**如下:

int i;

i = 1;

string s;

s = i.tostring();

(2)system.object和system.valuetype。

引用型別和值型別都繼承自system.object類。不同的是,幾乎所有的引用型別都直接從system.object繼承,而值型別則繼承其子類,即直接繼承system.valuetype。作為所有型別的基類,system.object提供了一組方法,這些方法在所有型別中都能找到。其中包含tostring方法及clone等方法。system.valuetype繼承system.object。它沒有新增任何成員,但覆蓋了所繼承的一些方法,使其更適合於值型別。

(3)值型別。

c#的所有值型別均隱式派生自system.valuetype:

結構體:struct(直接派生於system.valuetype)。

數值型別:整型,sbyte(system.sbyte的別名),short(system.int16),int(system.int32),long(system.int64),byte(system.byte),ushort(system.uint16),uint(system.uint32),ulong(system.uint64),char(system.char)。

浮點型:float(system.single),double(system.double)。

用於財務計算的高精度decimal型:decimal(system.decimal)。

bool型:bool(system.boolean的別名)。

使用者定義的結構體(派生於system.valuetype)。

列舉:enum(派生於system.enum)。

可空型別。

每種值型別均有乙個隱式的預設建構函式來初始化該型別的預設值。例如:

複製**

**如下:

int i = 0;

等價於:

int i = new int();

使用new運算子時,將呼叫特定型別的預設建構函式並對變數賦予預設值。在上例中,預設建構函式將值0賦給了i。

所有的值型別都是密封(seal)的,所以無法派生出新的值型別。

值得注意的是,system.valuetype直接派生於system.object。即system.valuetype本身是乙個類型別,而不是值型別。其關鍵在於valuetype重寫了equals()方法,從而對值型別按照例項的值來比較,而不是引用位址來比較。可以用type.isvaluetype屬性來判斷乙個型別是否為值型別:

複製**

**如下:

testtype testtype = new testtype ();

if (testtypetype.gettype().isvaluetype)

is value type.", testtype.tostring()); }

陣列(派生於system.array)

使用者需定義以下型別。

類:class(派生於system.object);

介面:inte***ce(介面不是乙個「東西」,所以不存在派生於何處的問題。介面只是表示一種contract約定[contract])。

委託:delegate(派生於system.delegate)。

object(system.object的別名);

字串:string(system.string的別名)。

可以看出:

引用型別與值型別相同的是,結構體也可以實現介面;引用型別可以派生出新的型別,而值型別不能;引用型別可以包含null值,值型別不能;引用型別變數的賦值只複製物件的引用,而不複製物件本身。而將乙個值型別變數賦給另乙個值型別變數時,將複製包含的值。

(5)記憶體分配。

值型別的例項經常會儲存在棧上的。但是也有特殊情況。如果某個類的例項有個值型別的字段,那麼實際上該字段會和類例項儲存在同乙個地方,即堆中。不過引用型別的物件總是儲存在堆中。如果乙個結構的字段是引用型別,那麼只有引用本身是和結構例項儲存在一起的(在棧或堆上,視情況而定)。如下例所示:

複製**

**如下:

public struct valuetypestruct

} valuetypestruct valuetypestructinstance = new valuetypestruct();

valuetypestructinstance.method();

//referencetypeobject 和 referencetypelocalvariable 都在哪存放?

單看valuetypestructinstance,這是乙個結構體例項,感覺似乎是整塊都在棧上。但是欄位referencetypeobject是引用型別,區域性變數referencetypelocalvarible也是引用型別。

public class referencetypeclass

public void method()

} referencetypeclass referencetypeclassinstance = new referencetypeclass();

// _valuetypefield在哪存放?

referencetypeclassinstance.method();

// valuetypelocalvariable在哪存放?

referencetypeclassinstance也有同樣的問題,referencetypeclassinstance本身是引用型別,似乎應該整塊部署在託管堆上。但字段_valuetypefield是值型別,區域性變數valuetypelocalvariable也是值型別,它們究竟是在棧上還是在託管堆上?

對上面的情況正確的分析是:引用型別在棧中儲存乙個引用,其實際的儲存位置位於託管堆。為了方便,簡稱引用型別部署在託管堆上。值型別總是分配在它宣告的地方,作為欄位時,跟隨其所屬的變數(例項)儲存;作為區域性變數時,儲存在棧上。

(6)辨明值型別和引用型別的使用場合。

在c#中,我們用struct/class來宣告乙個型別為值型別/引用型別。考慮下面的例子:

sometype onetypes = new sometype[100];

如果sometype是值型別,則只需要一次分配,大小為sometype的100倍。而如果sometype是引用型別,剛開始需要100次分配,分配後陣列的各元素值為null,然後再初始化100個元素,結果總共需要進行101次分配。這將消耗更多的時間,造成更多的記憶體碎片。所以,如果型別的職責主要是儲存資料,值型別比較合適。

一般來說,值型別(不支援多型)適合儲存供 c#應用程式操作的資料,而引用型別(支援多型)應該用於定義應用程式的行為。通常我們建立的引用型別總是多於值型別。如果滿足下面情況,那麼我們就應該建立為值型別:

該型別的主要職責用於資料儲存。

該型別的共有介面完全由一些資料成員訪問屬性定義。

該型別永遠不可能有子類。

該型別不具有多型行為。

答案:在c#中,變數是值還是引用僅取決於其資料型別。

c#的值型別包括:結構體(數值型別、bool型、使用者定義的結構體),列舉,可空型別。

c#的引用型別包括:陣列,使用者定義的類、介面、委託,object,字串。陣列的元素,不管是引用型別還是值型別,都儲存在託管堆上。

引用型別在棧中儲存乙個引用,其實際的儲存位置位於託管堆。簡稱引用型別部署在託管推上。值型別總是分配在它宣告的地方:作為欄位時,跟隨其所屬的變數(例項)儲存;作為區域性變數時,儲存在棧上。值型別在記憶體管理方面具有更好的效率,並且不支援多型,適合用做儲存資料的載體;引用型別支援多型,適合用於定義應用程式的行為。

**:

C 值型別與引用型別的區別

net將資料型別分為值型別 value type 和引用型別 reference type 乙個具有值型別 value type 的資料存放在棧 內的乙個變數中。即是在棧中分配記憶體空間,直接儲存所包含的值,其值就代表資料本身。值型別的資料具有較快的訪問速度。乙個具有引用型別 reference t...

值型別與引用型別區別

凡是直接繼承自system.valuetype的都是值型別,其他就是引用型別 區別就是乙個是傳值,乙個是傳引用 c 中值型別與引用型別的值傳遞與引用傳遞 值型別 結構體,數值型別 int,double,char,bool型,列舉,可空型別 nullable 引用型別 陣列,使用者定義的類 介面 委託...

c 值型別和引用型別《轉》

在c 中,值型別 整型 布林型 字元型 實數型 結構型 列舉型。引用型別 類 物件 字串 陣列 介面 委託。區別 1 值型別通常被分配在棧上,它的變數直接包含變數的例項,使用效率比較高。2 引用型別分配在託管堆上,引用型別的變數通常包含乙個指向例項的指標,變數通過該指標來引用例項。3 值型別繼承自v...