前言

之前有提到 C# Value Type、Reference Type 的差異,提到 String 是 Reference Type,可是在使用時卻很像 Value Type。

比較值

Value Type 以 int 為舉例

int a = 1;
int b = a;
a = 2;
Console.WriteLine(a == b); // 輸出: false

b 並沒有隨著 a 改變,看得出 int 是 Value Type。

string str1 = "abc";
string str2 = str1;
str1 = "def";
Console.WriteLine(str1 == str2); // 輸出:  false

修改 str1 卻沒有影響到 str2,所以會覺得 string 也是 Value Type(?)。

比較地址

使用 object.ReferenceEquals 來比較,假如是 Value Type,則會輸出 false

int a = 1;
int b = 1;
Console.WriteLine(object.ReferenceEquals(a, b)); // 輸出: false

int 確實是 Value Type,所以會輸出 false。

string str1 = "abc";
string str2 =  "abc";
Console.WriteLine(object.ReferenceEquals(str1, str2)); // 輸出: true

比較結果為 true,假如 String 是 Value Type,應該會與 int 的結果一樣會是 false。

也就是 String 其實是 Reference Type。

String 為什麼是 Reference Type

.NET 框架-string 是 value or reference type?

這裡面提到兩點

  • String 對象,若值相同,則其引用地址相同。

  • String 對象,若值不等,則其引用地址不等。

string str1 = "abc"; //str1指向記憶體位置 addressA 為 abc
string str2 = str1; //str2指向記憶體位置 addressA
str1 = "def"; //str1新指向記憶體位置 addressB 為 def
Console.WriteLine(str1 == str2); // 輸出:  false

String 特點

String 特點就是具有不可變性(immutable),一旦 new String 在記憶體(managed heap)上為它分配一塊連續記憶體空間,我們將不能以任何方式對這個 String 進行修改。所有對這個 String 進行各項操作而返回的 String,實際上是另一個重新 new 的 String,其本身並不會產生任何變化。

String 效能如何?

從上面就可以知道 String 有不可變性,一旦創建了就不能修改值,每次修改 String 都會產生一個新的 String,所以 String 效能比較低。

所以需要經常性操作 String 可以考慮使用 StringBuilder

結論

來自 ChatGPT 的解釋

C# String 有以下特性:

  • String 有不可變性:一旦創建 string,它的內容就不能被改變。

  • 賦值操作的實際行為:當執行 str = "abc" 時,實際上是創建了一個新的 string 對象,而不是修改原有的對象。然後,變量 str 被重新指向這個新對象。

  • 為什麼 str2 不變:當執行 string str2 = str1 時,str1 和 str2 確實指向了同一個對象。但是當 str1 被賦予新值時,它指向了一個新對象,而 str2 仍然指向原來的對象。

  • 值類型的行為:這種行為看起來很像值類型,但 string 仍然是引用類型。這是因為 string 的不可變性和特殊的內存管理方式。

  • 性能和內存管理:這種設計有助於提高性能和簡化內存管理,特別是在字符串被廣泛使用的情況下。

  • 字符串池(String Interning):C#使用字符串池來優化內存使用。相同的字符串字面量會指向內存中的同一位置。

這種行為是 C# 語言設計的一個特點,旨在結合引用類型的靈活性和值類型的一些優勢。它可能看起來有點反直覺,但在實際使用中通常是有益的。