** 目的 ** ** **
本文的目的在于揭示和 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 的别名 , 他们指向不同的内存空间。