您的位置:首页 > 编程语言 > C#

关于C# string的一些坑。

2016-03-08 15:28 423 查看
string简直是众说纷纭,各种说法一一展现,其实弄清楚这个之前,先搞清楚int类型是怎么存的,然后在研究引用类型是怎么存放的,就会完全玩转这些东西。

以下代码均经过vs2012实际验证。注意一点就是,一个引用表达式,其实占用了两个内存块:一个堆内存,一个栈内存。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace teststring

{

class Program

{

public test instance = new test();

public void run()

{

instance.s = "first";

instance.i = 1;

// callByValue(instance);

}

public void callByValue(test t)// 所有如此传递参数均是副本 ,如果是值类型不改变是因为复制了一份相同的。

{

t.s = "changed"; // 直接被改变。 t传的是引用的副本(栈区新开一个内存存放副本)。但是里面的地址值值还是一样的,引用地址值向的内容被改变。 其实 ,t.s 存的地址值在栈上,字符串changed在堆上。地址值指向changed。

// 字符串拘留池也是正确的,此处改变了引用指向。changed将会新创建一个引用堆。

t.i = 2;

}

public void callByValue1(test t)

{

test tem = new test();

tem.s = "456";

tem.i = 100;

t = tem; // 同样是引用的副本,改变的是引用副本里面的地址值,并没有真正改变test的地址值,指向也没有变化,所以无法改变。

}

static void Main(string[] args)

{

Program grm = new Program();

Console.WriteLine("{0}, {1}", grm.instance.s, grm.instance.i);// null,0

grm.run();

Console.WriteLine("{0}, {1}",grm.instance.s,grm.instance.i);//first,1

grm.callByValue(grm.instance);

Console.WriteLine("{0}, {1}", grm.instance.s, grm.instance.i);//changed,2

grm.callByValue1(grm.instance);

Console.WriteLine("{0}, {1}", grm.instance.s, grm.instance.i);//changed,2

Console.ReadLine();

}

}

class test

{

public string s = null;

public int i = 0;

}

}

补充一下。字典之类的也一样。传入的也是副本地址,但是副本地址指向的内容清空后会造成实参内容清空。同时还要注意的是,两个字典赋值,如果是非引用类型。则清空互不影响,如果是引用类型,则仍然会互相影响,相同的道理,给的是地址值,都指向同一块内存。

若有看不懂请留言。原创内容,转载说明
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: