本文的目的在於揭示和DOTNET及C#相關的一些常見的和不常見的問題。在這些問題中我的第一篇文章和string數據類型有關,string數據類型是一種引用類型,但是當和其他引用類型比較的時候,很多開發人員可能並不能完全理解它的行為。
問題
對於常見的引用類型,當改變一個對象別名的值時,這種變化也同樣會在一個實際的對象中表現出來;反之亦然。但是對於string類型,似乎不是這樣的。
解釋
引用類型
假設我們有一個類MyType,這個類有一個屬性Name;我們還有一個類AppType,這個類提供Main()方法來運行這個程序。
下面,我們來看看代碼:
using System;
class MyType
{
private string name;
public string Name
{
set
{
name=value;
}
get
{
return name;
}
}
}
class AppType
{
public static void Main()
{
MyType obj1,obj2;
Console.WriteLine("*****Learning reference Philosophy*****");
obj2=new MyType();
obj2.Name="Sadiq";
obj1=obj2;
Console.WriteLine("values of obj1={0} and obj2={1}",obj1.Name,obj2.Name);
obj1.Name="Ahmed";
Console.WriteLine("values of obj1={0} and obj2={1}",obj1.Name,obj2.Name);
}
}
當你編譯並且運行這段代碼時,你將得到如下輸出:
*****Learning reference philosophy*****
values of obj1=Sadiq and obj2=Sadiq
values of obj1=Ahmed and obj2=Ahmed
這表明obj1不過是obj2的別名,換句話說,obj1和obj2都指向同一個內存空間。
值類型
和上面的代碼差不多,不同的是這次我們將MyType定義為類,其他部分都相同,我們先看看代碼:
using System;
struct MyType
{
private string name;
public string Name
{
set
{
name=value;
}
get
{
return name;
}
}
}
class AppType
{
public static void Main()
{
MyType obj1,obj2;
Console.WriteLine("*****Learning reference Philosophy*****");
obj2=new MyType();
obj2.Name="Sadiq";
obj1=obj2;
Console.WriteLine("values of obj1={0} and obj2={1}",obj1.Name,obj2.Name);
obj1.Name="Ahmed";
Console.WriteLine("values of obj1={0} and obj2={1}",obj1.Name,obj2.Name);
}
}
我們再來看看上面代碼運行後的輸出:
*****Learning reference philosophy*****
values of obj1=Sadiq and obj2=Sadiq
values of obj1=Ahmed and obj2=Sadiq
這表明obj1和obj2並不相同,也就是說,他們指向不同的內存空間。
引用類型還是值類型?
現在,讓我們看看直接使用string類型的情況:
using System;
class AppType
{
public static void Main()
{
String obj1,obj2;
Console.WriteLine("*****Learning reference philosophy*****");
//No need of it
//obj2=new MyType();
obj2="Sadiq";
obj1=obj2;
Console. WriteLine("values of obj1={0} and obj2={1}",obj1,obj2);
obj1="Ahmed";
Console.WriteLine("values of obj1={0} and obj2={1}",obj1,obj2);
}
}
當你運行這段代碼,你會得到:
*****Learning reference philosophy*****
values of obj1=Sadiq and obj2=Sadiq
values of obj1=Ahmed and obj2=Sadiq
這表明obj1並不是obj2的別名,即obj1和obj2指向不同的內存空間。
非常奇怪!確實!我們都知道string類型是動態增長的,這表明它必須在堆上分配內存。我們都知道引用類型都在堆上分配內存,那麼string類型也應該是引用類型,那麼為何它又表現出和值類型一樣的性質呢?
原因
關鍵在於如下的兩行代碼中:
string obj1;
obj1 = “value forces to allocate a memory”;
第一行代碼僅僅是定義了一個對象,並不會創建一個對象;第二行代碼才會真正創建一個對象。這意味著你也可以將第二行代碼寫成:
obj=new string(“value forces to allocate a memory”);.
總結
因此,當你初始化一個string對象的值或是賦予一個新的字符串給它的時候都將在內存中創建一個新的對象。現在,我們應該明白了第三個例子中的obj1並不是obj2的別名,他們指向不同的內存空間。