簡體   English   中英

為什么 String 是 Value 類型,盡管它是類而不是結構?

[英]Why String is Value type although it is a class not a struct?

舉個例子:

string me = "Ibraheem";
string copy = me;
me = "Empty";
Console.WriteLine(me);
Console.WriteLine(copy);

輸出是:

Empty
Ibraheem

由於它是類類型(即不是結構),字符串copy也應該包含Empty ,因為 C# 中的= operator分配對象的引用而不是對象本身(如在 C++ 中)?

雖然接受的答案解決了這個問題(和其他一些人一樣),但我想給出一個專門針對您實際要求的答案,即關於變量賦值的語義。

C# 中的變量只是被留出用於保存單個值的內存片段。 重要的是要注意,沒有“值變量”和“參考變量”之類的東西,因為變量只保存值。

“值”和“參考”之間的區別在於類型。 值類型 (VT) 意味着整條數據都存儲在變量中。

如果我有一個名為abc的整數變量保存值100 ,那么這意味着我的應用程序中有一個四字節的內存塊,其中存儲了文字值100 這是因為int是一種值類型,因此所有數據都存儲在變量中。

另一方面,如果我有一個名為foostring變量,其中包含值"Adam" ,則涉及兩個實際的內存位置。 第一個是存儲實際字符"Adam"的內存,以及關於我的字符串的其他信息(它的長度等)。 然后將對該位置的引用存儲在我的變量中。 引用與 C/C++ 中的指針非常相似; 雖然它們不一樣,但類比足以解釋這種情況。

因此,總而言之,引用類型的值是對內存中另一個位置的引用,其中值類型的值是數據本身

當您將某些內容分配給變量時,您要更改的只是該變量的value 如果我有這個:

string str1 = "foo";
string str2 = str1;

然后我有兩個保存相同值的字符串變量(在這種情況下,它們每個都保存對相同字符串"foo"的引用。)如果然后這樣做:

str1 = "bar";

然后我將str1的值更改為對字符串"bar"的引用。 這根本不會改變str2 ,因為它的值仍然是對字符串"foo"的引用。

System.String不是值類型。 它表現出一些類似於值類型的行為,但您遇到的行為不是其中之一。 考慮以下代碼。

class Foo 
{ 
     public string SomeProperty { get; private set; }
     public Foo(string bar) { SomeProperty = bar } 
}

Foo someOtherFoo = new Foo("B");
Foo foo = someOtherFoo;
someOtherFoo = new Foo("C");

如果您檢查了foo.SomeProperty的輸出,您是否希望它與someOtherFoo.SomeProperty相同? 如果是這樣,您對語言的理解有缺陷。

在您的示例中,您已為字符串分配了一個值。 而已。 它與值類型、引用類型、類或結構無關。 這是一個簡單的賦值,無論您是在談論字符串、長整數還是 Foos 都是如此。 您的變量暫時包含相同的值(對字符串“Ibraheem”的引用),但隨后您重新分配了其中一個。 這些變量並不是一直都密不可分的,它們只是暫時保持着一些共同點。

它不是一個值類型。 當您使用字符串文字時,它實際上是在編譯時存儲的引用。 所以當你分配一個字符串時,你基本上是在改變指針,就像在 C++ 中一樣。

字符串的行為與任何其他類相同。 考慮:

class Test {
    public int SomeValue { get; set; }
    public Test(int someValue) { this.SomeValue = someValue; }
}

Test x = new Test(42);
Test y = x;
x = new Test(23);
Console.WriteLine(x.SomeValue + " " + y.SomeValue);

輸出:

23 42

– 與您的string示例中的行為完全相同。

您的示例顯示的是字符串是引用類型的經典行為。

string copy = me; 意味着copy引用將指向me指向的相同內存位置。

稍后me可以指向其他內存位置,但不會影響copy

如果您也使用值類型,您的代碼也會這樣做。 考慮使用整數:

int me = 1;
int copy = me;
me = 2;
Console.WriteLine(me);
Console.WriteLine(copy);

這將打印出以下內容:

2
1

雖然其他答案確切地說明了您的答案的解決方案是什么,但為了更好地了解為什么您需要讀取堆和堆棧內存分配以及垃圾收集器何時從內存中刪除數據。

這是一個很好的頁面,描述了堆棧和堆內存以及垃圾收集器。 文章底部有其他部分解釋的鏈接: http ://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx?ArticleID=9adb0e3c-b3f6-40b5-98b5-413b6d348b91

希望這能讓你更好地理解為什么

回答原來的問題:

C# 中的字符串是具有值類型語義的引用類型。

它們被存儲在堆上,因為由於堆棧的大小有限,將它們存儲在堆棧上可能不安全。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM