关于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;
}
}
补充一下。字典之类的也一样。传入的也是副本地址,但是副本地址指向的内容清空后会造成实参内容清空。同时还要注意的是,两个字典赋值,如果是非引用类型。则清空互不影响,如果是引用类型,则仍然会互相影响,相同的道理,给的是地址值,都指向同一块内存。
若有看不懂请留言。原创内容,转载说明
以下代码均经过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;
}
}
补充一下。字典之类的也一样。传入的也是副本地址,但是副本地址指向的内容清空后会造成实参内容清空。同时还要注意的是,两个字典赋值,如果是非引用类型。则清空互不影响,如果是引用类型,则仍然会互相影响,相同的道理,给的是地址值,都指向同一块内存。
若有看不懂请留言。原创内容,转载说明
相关文章推荐
- C#方法
- CSV文件一键生成CSharp文件
- C#写的windows应用程序打包
- LINQ查询
- C#成魔之路<9>文件及数据流技术(2)
- 【C#】C#读取Excel中的数据
- C#中正则表达式的使用
- C#向客户端注册脚本的几种方法
- C#路途之 类(1) public
- c#大圣之路笔记——c# 通过页面把excel中的数据导入到DB中
- C# 指定Webbrowser控件所用IE内核版本
- 通过rtf字符串往richTextBox中添加带有文字的表格
- C#实现客户端弹出消息框封装类实例
- C#第五节课
- 絮絮叨叨学SuperMap组件式开发(.net)
- 可选参数 和 TryParse用法(C#)
- C#索引器2 字符串作为索引号
- C#索引器1 数字作为索引号
- C# Socket
- C#操作图片存入XML和显示XML图片