引用型別和值型別

2021-04-14 15:31:02 字數 3866 閱讀 2132

c#是一種型別安全的語言。每乙個變數都要求定義為乙個特定的型別,並且要求儲存在變數中的值只能是這種型別的值。

變數既能儲存值型別,也可以儲存引用型別,還可以是指標。這一課將講述前兩種型別,關於指標的討論我們將在下一課中進行。

下面是關於值型別和引用型別不同點的概論:

如果乙個變數v儲存的是值型別,則它直接儲存包含資料的物件。任何其他的變數v』都不能直接儲存已經由v儲存了的物件,雖然v』可以儲存乙個和v儲存的物件有著相同值的物件。(譯註:這意味著,v和v』儲存的物件毫不相干,任意改變其中乙個儲存的物件都不會影響到另乙個變數儲存的物件。)

如果變數v儲存的是乙個引用型別,它直接儲存乙個指向物件的引用,同時可能存在另乙個變數v』,它也儲存著指向這個物件的引用。(譯註:這意味著,改變v』引用的物件同時也會影響到v引用的物件,反之亦然。)

值型別

在c#中你可以通過宣告列舉型別或是結構型別來定義你自己的值型別。c#以同樣的方式處理使用者自定義的型別和c#預定義的值型別,不過c#編譯器可能更優於處理後者。下面的表列出了c#中預定義的值型別的一些資訊。因為在c#中所有的基本值型別都是從object型別(最終基類)發展而來,所以下表中還顯示了與這些預定義型別相對應的.net框架中的system型別。

c# 型別

.net 框架型別

有無符號

佔據位數

取值範圍

sbyte

system.sbyte 是

1-128 到 127

short

system.int16 是

2-32768 到32767

intsystem.int32 是

4-2147483648 到 2147483647

long

system.int64 是

8-9223372036854775808 到 9223372036854775807

byte

system.byte 否

10 到 255

ushort

system.uint16 否

20 到 65535

uint

system.uint32 否

40 到 4294967295

ulong

system.uint64 否

80 到18446744073709551615

float

system.single 是

4可能值從±1.5 x 10-45 到 ±3.4 x 1038 ,小數點後7位有效數字

double

system.double 是

8可能值從±5.0 x 10-324 to ±1.7 x 10308 小數點後15到16位有效數字

decimal

system.decimal 是

12可能值從±1.0 x 10-28

到±7.9 x 1028 小數點後28到29位有效數字

char

system.char

n/a 2

任何16位unicode字元

bool

system.boolean

n/a1 / 2

true 或者false

在下面的**中,兩個變數都宣告為整形,並得到賦值:

int x = 10;

int y = x;

y = 20; // 這條語句執行後x的值為10,y的值為20;

引用型別

c#預定義的引用型別包括object和string型別。正如我們在上面提到的,object型別是所有其他型別的最終基類。使用者定義的引用型別可以是介面型別、類型別和委託型別(第12課會有具體介紹)。

引用型別事實上儲存乙個指向它引用的物件的記憶體位址。下面的**段中有兩個變數引用了同乙個物件(本例中,假設這個物件有乙個資料成員』myvalue』):

object x = new object();

x.myvalue = 10;

object y = x;

y.myvalue = 20; // 這條語句執行後,x.myvalue和y.myvalue的值都為20。

上面的這段**演示了引用型別的乙個特點:改變某乙個引用指向的物件的屬性同時也會影響到所有其他指向這個物件的引用。不過,strings型別雖然也是引用型別,但它的工作方式更象值型別。當乙個字串被指定了另乙個字串的值時,例如:

string s1 = "hello";

string s2 = s1;

s2和s1都引用了同乙個字串型別,但是當s1的值發生改變時,例如s1=」goodbye」;s2的值仍然是」hello」。之所以會這樣,是因為當改變s1的值是,新建立了乙個string物件,s1引用這個新的string物件;s2仍然引用原來string物件。產生這種行為的原因是string物件是恆定的,也就是說,一旦乙個string物件被建立,它的值就不能再修改,所以當改變乙個字串變數的值的時候,僅僅是新建立了乙個包含修改內容的新的string物件。

轉義序列和逐字字串(verbatim strings)

當宣告乙個字串變數時有一些字元是不能以平常的方式包含在變數中的。為了解決這個問題,c#提供了兩種不同的方法。

第一種方法是使用』轉義序列』。例如,我們想得到如下的字串

「hello world

how are you」

我們可以使用下面的語句宣告字串:string a = "/"hello world/nhow are you/""。這條語句中使用了」和換行符的轉義序列。更多字元的轉義序列可以參見下表:

character

escape sequence'

/' "

/" /

// 警報

/a退格符 /b

換頁符 /f

換行符 /n

回車符 /r

tab 符 /t

垂直tab 符 /v

使用數字指定的unicode 字元,如/u2000 /u

使用十六進製制數指定的unicode 字元,如/xc8 /x

空值/0 (zero

第二種方法是使用』逐字字串』文字。這種方法將想要得到的字串放在@」和」之間。假如我們需要將c:/my documents/賦值給』path』,我們可以使用轉義序列方法:string path = "c://my documents//";也可以使用如下的語句:string path = @"c:/mydocuments/"。

通過使用後一種方法得到的字串還可以橫跨多行而不需要使用』/n』。使用這種方法唯一需要使用到轉義序列的字串是」,其轉義字元為」」(兩個連在一起的雙引號)。例如想將the word "big" contains three letters.賦值給』text』,我們就可以使用如下的語句:string text = @"the word ""big"" contains three letters."。

裝箱

c#允許你將任何的值型別轉換為對應的引用型別,也可以將得到的引用型別再轉換為值型別。下面的**演示了這種轉換――裝箱:

int i = 123;

object box = i;

if (box is int)

// 這一行將會列印出來。

當第2行的**執行後,物件』box』將被初始化,i儲存的值將被複製給這個物件。值得注意的一件趣事是box執行時的型別將是被裝箱的值型別(本例中即為int)。』is』操作符將返回box的型別為int。

引用型別和值型別

c 中值型別和引用型別作為方法引數傳遞的時候其實都可以說是 值 的傳遞,只不過這裡的 值 指代的東西有所區別。當方法的引數為值型別時,方法傳遞的是值本身的值。當方法的引數為引用型別時,方法傳遞的則是應用型別的引用的位址,也就是引用型別位址在棧上的值。舉個引用型別作為引數傳遞的例子 static vo...

值型別和引用型別

為了更好地說明兩種型別之間的區別,借用如下的 來說明 值型別引用型別 記憶體分配地點 分配在棧中 分配在堆中 效率效率高,不需要位址轉換 效率低,需要進行位址轉換 記憶體 使用完後,立即 使用完後,不是立即 等待gc 賦值操作 進行複製,建立乙個同值新物件 只是對原有物件的引用 函式引數與返回值 是...

值型別和引用型別

變數 常量和杖舉 常量 用來代替乙個數或字串的名稱,我們可以在初始化時定義。在變數前增加關鍵字 const 就可以把這個變數設定為常量。語法如下 訪問修飾符 const 資料型別 常量名 值 注 常量在使用過程中是不能被修改的,如果要修改乙個常量的話程式會發生錯誤。杖舉 事先考慮到某一變數可能取得值...