记录一下C#深拷贝的几种方式
一、C#中预定义数据类型
1》值类型
2》引用类型
两种类型的不同点:
概念:值类型直接存储其值,而引用类型存储对值的引用
存储:值类型存储在堆栈(stack)上,而引用类型存储在托管堆上(managed heap)。
当使用值类型,进行赋值的操作时,将1个变量的值赋值给另外1个变量,例如
int x = 10;
int y = x;
y = 20;
这表示上面的语句会在内存中的两个地方存储值10。这样直接更改y变量的值时,不会影响到x的值。
当使用引用类型,进行赋值的操作时,例如
List<int> listNum = new List<int>();
listNum.add(1);
listNum.add(2);
listNum.add(3);
List<int> listNum1 = listNum;
listNum.Clear();
listNum.Count;
listNum1.Count;
当我们访问两个变量的数量时,都为0。
首先,listNum和listNum1,都是引用类型的变量,它们都指向包含该内存的位置,引用类型变量的赋值,只保留了一个引用,因为两个变量都指向了一块内存地址,所以对两个变量中任何一个变量的操作都会影响到另外一个。
那么该怎么办呢?我们可以通过深拷贝的方式解决上面的问题。
通过以下几种方式,实现深拷贝。
1、最简单直接的是,循环变量赋值
private static List<int> DeepCopyData(List<int> list)
{//此处使用new关键字,创建了对象,所以该变量指向了个新的引用List<int> listDeep = new List<int>();for(var i=0;i<list.Count;i++){var item = list[i];listDeep.Add(item);}return listDeep;
}
因为在函数体中,直接创建了新的对象,在进行其他操作,就不会影响另外一个变量了。
2、通过JsonConvert,序列化和反序列化操作
public static T DeepCopyJson<T>(T obj){// 序列化string json = JsonConvert.SerializeObject(obj);// 反序列化return JsonConvert.DeserializeObject<T>(json);}
3、通过XmlSerializer和内存流
private static T DeepCopyXml<T>(T obj)
{object rel;using (MemoryStream ms = new MemoryStream()){XmlSerializer xml = new XmlSerializer(typeof(T));xml.Serialize(ms, obj);ms.Seek(0, SeekOrigin.Begin);rel = xml.Deserialize(ms);ms.Close();}return (T)rel;
}
4、通过BinaryFormatter和内存流
private static T DeepCopyBinary<T>(T obj)
{object rel;using (MemoryStream ms = new MemoryStream()){BinaryFormatter bf = new BinaryFormatter();bf.Serialize(ms, obj);ms.Seek(0, SeekOrigin.Begin);rel = bf.Deserialize(ms);ms.Close();}return (T)rel;
}
5、通过DataContractSerializer和内存流
private static T DeepCopyDataContract<T>(T obj)
{object rel;using(MemoryStream ms = new MemoryStream()){DataContractSerializer ser = new DataContractSerializer(typeof(T));ser.WriteObject(ms, obj);ms.Seek(0, SeekOrigin.Begin);rel = ser.ReadObject(ms);ms.Close();}return (T)rel;
}