赛尔号麒麟怎么获视:C#中的string 不是引用型的吗?

来源:百度文库 编辑:杭州交通信息网 时间:2024/04/30 12:43:34
看下面的程序:
public class Class1
{
private string str = "Class1.str";
private int i = 0;
static void StringConvert(string str)
{
str = "string being converted.";
}
static void StringConvert(Class1 c)
{
c.str = "string being converted.";
}
static void Add(int i)
{
i++;
}
static void AddWithRef(ref int i)
{
i++;
}
static void Main()
{
int i1 = 10;
int i2 = 20;
string str1 = "str";
Class1 c = new Class1();

Add(i1);
AddWithRef(ref i2);
Add(c.i);
StringConvert(str1);
StringConvert(c);
Console.WriteLine(i1);
Console.WriteLine(i2);
Console.WriteLine(c.i);
Console.WriteLine(str1);
Console.WriteLine(c.str);
Console.ReadLine();
}
}
为什么结果是:
10
21
0
str
string being converted.
而不是
10
21
0
string being converted
string being converted.
呢?
既然是引用型的,str1在被传入后应该被改变啊!

为了解释这个问题,我特意写了如下代码:

class Program
{
static void Main(string[] args)
{
Person p = new Person("Allen Lee");
Console.WriteLine(p.Name);
ChangePerson(p, "Martin Ko");
Console.WriteLine(p.Name);

Console.WriteLine();

string text = "Original Text";
Console.WriteLine(text);
ChangeText(text);
Console.WriteLine(text);
}

static void ChangePerson(Person p, string name)
{
p = new Person(name);
}

static void ChangeText(string text)
{
text = "Changed Text";
}
}

class Person
{
public Person(string name)
{
m_Name = name;
}

private string m_Name;
public string Name
{
get { return m_Name; }
}
}

程序的输出是:

Allen Lee
Allen Lee

Original Text
Original Text

正如你所看到,我在代码中做了两种测试,一种是针对普通引用类型 Person,另一种就是 string。你的代码中 StringConvert 方法里面的

str = "string being converted.";

就相当于我的代码中 ChangePerson 方法里面的

p = new Person(name);

C# 明确规定在方法体内对参数进行这种重新赋值不会影响客户端的原对象,方法结束后一切将还原。而你代码中重载版本的 StringConvert 方法里面的

c.str = "string being converted.";

是修改对象字段,这却是会影响客户端的原对象。而值类型和引用类型的一个区别也在这里,假如我把代码修改如下:

struct Person
{
public Person(string name)
{
m_Name = name;
}

private string m_Name;
public string Name
{
get { return m_Name; }
set { m_Name = value; }
}
}

static void ChangePerson(Person p, string name)
{
p.Name = name;
}

那么输出结果将和刚才的一样,因为 C# 规定在方法体内修改值类型的字段不会影响到客户端的原对象。

那么,如何才能获得你所期望的输出呢?首先,你得先清楚你要做的是什么,由于 string 是一个不可变(Immutable)类型,一旦被初始化,你就不能再改变该 string 对象的内容了,但你希望让参数类面的改动影响到客户端,于是你就只能改变客户端的 string 变量的指向了。需要提醒的是,引用类型变脸实质上是一个托管指针,它里面存放着其指向对象的地址。由于我们无法改变 string 对象的内容,我们就只好改变 string 变量的内容,即那个指针地址了,这个时候你就需要用到 ref/out 关键字了,以下是修改后的 StringConvert:

static void StringConvert(ref string str)
{
str = "string being converted.";
}

而 StringConvert 的使用也需要做稍许改动:

StringConvert(ref str);

值得注意的是,ref 和 out 是有小小区别的,由于篇幅的问题我不能再继续解释了,况且网上有很多这样的文章。

Hope that helps.