为什么要用到深拷贝呢?比如我们建了某个类Person,并且实例化出一个对象,然后,突然需要把这个对象复制一遍,并且复制出来的对象要跟之前的一模一样,来看下我们一般会怎么做,看代码
public class Person
{
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
Person sourceP = new Person() { Name = "大哥" };
Person copyP = sourceP;
copyP.Name = "大哥大"; // 拷贝对象改变Name值
// 结果都是"大哥",因为实现的是浅拷贝,一个对象的改变都会影响到另一个对象
Console.WriteLine("Person.Name: [SourceP: {0}] [CopyP:{1}]", sourceP.Name, copyP.Name);
Console.Read();
}
}
运行结果如图
可以看到虽然复制了一份sourceP对象,但是修改新对象copyP的Name属性时,居然把原来的sourceP对象的值也改了。这里的原理是因为“=”号,在对引用类型使用时,仅仅是新建一个新的引用变量,然后把引用地址复制给了新的引用变量而已,并没有复制真正的内容,这时候如果需要复制真正内容的话,就需要用到深拷贝的方式了。
几种常见的深拷贝方式
1、利用反射实现
public static T DeepCopyByReflection<T>(T obj)
{
if (obj is string || obj.GetType().IsValueType)
return obj;
object retval = Activator.CreateInstance(obj.GetType());
FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance);
foreach(var field in fields)
{
try
{
field.SetValue(retval, DeepCopyByReflection(field.GetValue(obj)));
}
catch { }
}
return (T)retval;
}
2、利用二进制序列化和反序列化
public static T DeepCopyByBinary<T>(T obj)
{
object retval;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
retval = bf.Deserialize(ms);
ms.Close();
}
return (T)retval;
}
注意,使用二进制序列化和反序列化时,在需要序列化的类上要加上[Serializable]
[Serializable]
public class Person
{
public string Name { get; set; }
}
3、利用xml序列化和反序列化
public static T DeepCopyByXml<T>(T obj)
{
object retval;
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer xml=new XmlSerializer(typeof(T));
xml.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
retval = xml.Deserialize(ms);
ms.Close();
}
return (T)retval;
}
这是我所学到的一些知识,在此分享给大家,希望可以帮助到你们。
以上就是我的分享,新手上道,请多多指教。如果有更好的方法或不懂得地方欢迎在评论区教导和提问喔!