C#中的浅拷贝与深拷贝

一、浅拷贝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中实现方式:

  1. 反射
  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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值