一、浅拷贝和深拷贝
- 浅拷贝:创建一个新对象,对于值类型,栈内容是其值本身;对于引用类型,其值是指向堆的内存地址(它们是共享内存的,如果原对象或新对象中的一个改变了这个地址上的值,就会影响到另一个对象)。
- 深拷贝:创建一个一摸一样的新对象,对于引用类型,它们是不共享内存的,新对象会从堆内存开辟一个新的区域存放(两者互不影响)。
二、结构体Struct
C#中 结构体struct 是值传递、浅拷贝
测试代码如下:
public struct Record
{
public int id;
public string name;
public int[] children;
}
public static void DoSomething(Record record)
{
record.id = 6;
record.name = "Bob";
record.children[0] = 7;
unsafe
{
fixed (char* p2 = record.name)
{
Console.WriteLine((int)p2);
}
}
}
static void Main(string[] args)
{
Record record = new Record();
record.name = "Alice";
record.children = new int[] { 1, 2, 3 };
unsafe
{
fixed (char* p1 = record.name)
{
Console.WriteLine((int)p1);
}
}
DoSomething(record);
Console.WriteLine(string.Format("{0}-{1}-{2}",record.id
, record.name, record.children[0]));
}
上面的例子中,声明的结构体:
在调用DoSomething() 之前的值为: { 0,“Alice”,{1,2,3}}
在DoSomething()中,浅拷贝过来的值为 { 6,“Bob”,{7,2,3}}
id 是 值类型,所以出了函数作用域就没有影响,
name 是 string类型,在C#中属于引用类型。
【C#在对一个字符串赋值时,是先为右值开辟新的内存空间,然后把右值的引用赋给左值】
当它在函数域中被赋值为“Bob”时,其实是赋了一个新的地址(指向“Bob”的地址)给浅拷贝过来的地址,对原来的struct不起作用。
(示例中的unsafe代码就是为了看出两个字符串的地址区别)children数组是引用类型,浅拷贝了它的引用给函数,函数中对引用的地址上的值进行了修改,会影响原来的struct。
所以执行完DoSomething()后 结构体值为 { 0,“Alice", { 7, 2, 3 }}
总结
结构体是值传递、浅拷贝。
结构体成员中,对于引用类型,只拷贝引用,引用里的值不拷贝。
所以,浅拷贝后
对引用的指针位置修改,对struct不起作用。
对引用的地址上的值进行修改,会对struct起作用。