一、浅拷贝VS深拷贝
1.浅拷贝:拷贝一个对象时,对于对象的值类型成员会复制其背身;对于对象的引用类型成员,仅仅复制对象引用,这个引用指向托管堆上的对象实例。
例子:一个人叫张三,后改名字为李四。不过这个张三或李四做出如何动作,都反应在同一个人身上。
Person personSource = new Person() { name = "张三" };
Person personCopy = personSource; //浅拷贝
personCopy.name = "李四"; //拷贝对象改变Name值
Console.WriteLine("Source:Name={0};", personSource.name);
Console.WriteLine("Copy:Name={0};", personCopy.name);
2.深拷贝:对引用类型成员也进行复制,在托管堆上赋值原先对象实例所包含的数据,再在托管堆上创建新的对象实例。
例子:一个人叫张三,通过克隆技术克隆张三来生成另一个人-李四,这样张三与李四则是相互独立,互不影响。
int iSource = 5210;
//值类型成员执行深拷贝
int iCopy = iSource;
Console.WriteLine("Copy:" + iCopy);
Console.WriteLine("Source:" + iSource);
//对拷贝对象赋值,不会改变源对象的值
iCopy = 10;
Console.WriteLine("Copy:" + iCopy);
Console.WriteLine("Source:" + iSource);
//对源对象赋值,也不会改变拷贝对象的值
iSource = 210;
Console.WriteLine("Copy:" + iCopy);
Console.WriteLine("Source:" + iSource);
二、浅拷贝实现及验证
所有对象都是继承于System.Object,这个对象中有一个MemberwiseClone()方法,该方法就可以用来实现浅拷贝。具体代码如下:
class Program
{
static void Main(string[] args)
{
ShallowCopyDemo();
Console.ReadLine();
}
/// <summary>
/// 浅拷贝
/// </summary>
public static void ShallowCopyDemo()
{
ShallowCopyDemoClass DemoA = new ShallowCopyDemoClass();
ShallowCopyDemoClass DemoB = DemoA.Clone() as ShallowCopyDemoClass;
DemoB.intValue = 2;
WriteLog(string.Format("int->[A:{0}] [B:{1}]", DemoA.intValue, DemoB.intValue));
DemoB.strValue = "2";
WriteLog(string.Format("string->[A:{0}] [B:{1}]", DemoA.strValue, DemoB.strValue));
DemoB.pEnum = PersonEnum.EnumB;
WriteLog(string.Format("Enum->[A: {0}] [B:{1}]", DemoA.pEnum, DemoB.pEnum));
DemoB.pStruct.StructValue = 2;
WriteLog(string.Format("struct->[A: {0}] [B: {1}]", DemoA.pStruct.StructValue, DemoB.pStruct.StructValue));
DemoB.pIntArray[0] = 2;
WriteLog(string.Format("intArray->[A:{0}] [B:{1}]", DemoA.pIntArray[0], DemoB.pIntArray[0]));
DemoB.pStringArray[0] = "2";
WriteLog(string.Format("stringArray->[A:{0}] [B:{1}]", DemoA.pStringArray[0], DemoB.pStringArray[0]));
DemoB.pClass.Name = "2";
WriteLog(string.Format("Class->[A:{0}] [B:{1}]", DemoA.pClass.Name, DemoB.pClass.Name));
}
static void WriteLog(string strMsg)
{
Console.WriteLine(strMsg);
}
}
class ShallowCopyDemoClass : ICloneable
{
public int intValue = 1;
public string strValue = "1";
public PersonEnum pEnum = PersonEnum.EnumA;
public PersonStruct pStruct = new PersonStruct() { StructValue = 1 };
public Person pClass = new Person("1");
public int[] pIntArray = new int[] { 1 };
public string[] pStringArray = new string[] { "1" };
#region ICloneable成员
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
}
class Person
{
public string Name;
public Person(string name)
{
Name = name;
}
}
public enum PersonEnum
{
EnumA = 0,
EnumB = 1
}
public struct PersonStruct
{
public int StructValue;
}
由输出弹框中的内容可得:
1.int、string(特殊)、Enum、struct等值类型,源对象与拷贝对象的值不一致,属于深拷贝;
2.数组、类等引用类型,源对象与拷贝对象的值一直,属于浅拷贝。
三、深拷贝实现及验证
深拷贝有3中实现方式:
- 反射
- 反序列化
- 表达式树
先看看前2中实现方式:
反射:
public class DeepCopyHelper
{
public static T DeepCopyWithReflection<T>(T obj)
{
Type type = obj.GetType();
//如果是字符串或值类型,直接返回对象
if (obj is string || type.IsValueType)
{
return obj;
}
if (type.IsArray)
{
Type elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));
var array = obj as Array;
Array copied = Array.CreateInstance(elementType, array.Length);
for (int i = 0; i < array.Length; i++)
{
copied.SetValue(DeepCopyWithReflection(array.GetValue(i)), i);
}
return (T)Convert.ChangeType(copied, obj.GetType());
}
object retval = Activator.CreateInstance(obj.GetType());
PropertyInfo[] properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
foreach (var property in properties)
{
var propertyValue = property.GetValue(obj, null);
if (propertyValue == null)
{
continue;
}
property.SetValue(retval, DeepCopyWithReflection(propertyValue), null);
}
return (T)retval;
}
}
[Serializable]
public class DeepCopyDemoClass
{
public string Name { get; set; }
public int[] pIntArray { get; set; }
public Address Address { get; set; }
public DemoEnum DemoEnum { get; set; }
public override string ToString()
{
return "DeepCopyDemoClass";
}
}
[Serializable]
public struct Address
{
public string City { get; set; }
}
public enum DemoEnum
{
EnumA = 0,
EnumB = 1
}
class Program
{
static void Main(string[] args)
{
DeepCopyDemo();
Console.ReadLine();
}
}
反序列化:
// 利用XML序列化和反序列化实现
public static T DeepCopyWithXmlSerializer<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;
}