📜  浅拷贝与深拷贝 c# (1)

📅  最后修改于: 2023-12-03 15:11:05.545000             🧑  作者: Mango

浅拷贝与深拷贝

在 C# 编程语言中,当我们需要拷贝一个对象时,经常需要面对浅拷贝和深拷贝的问题。简单的说,浅拷贝是在拷贝对象时只复制对象的地址而不复制对象本身,而深拷贝则是同时复制对象和对象的所有子对象。

浅拷贝

浅拷贝仅仅是将对象的引用复制给了目标对象,实际上两个对象指向的是同一块内存区域。当原对象的属性值变化时,目标对象的属性值也会随之变化。

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Person person1 = new Person { Name = "张三", Age = 18 };
Person person2 = person1;

person2.Age = 20;

Console.WriteLine(person1.Age); // 输出:20

在上面的例子中, person2 实际上是指向 person1 的引用。当我们修改 person2.Age 的值时,person1.Age 的值也跟着变化了,这就是浅拷贝的问题所在。

深拷贝

为了解决浅拷贝的问题,我们可以使用深拷贝来复制对象数据。它会同时复制对象和对象的所有子对象,新的对象和原来的对象没有任何引用关系,修改其一不会影响另一个。

C# 中实现深拷贝的方式有很多,下面演示两种常用方式。

通过序列化和反序列化实现深拷贝

使用 System.Runtime.Serialization 命名空间下的 DataContractSerializer,需要序列化对象和反序列化得到新的对象。

public static T DeepCopy<T>(T obj)
{
    var dcSer = new DataContractSerializer(typeof(T));
    using (var ms = new MemoryStream())
    {
        dcSer.WriteObject(ms, obj);
        ms.Position = 0;
        return (T)dcSer.ReadObject(ms);
    }
}
使用反射实现深拷贝

使用反射来遍历对象中的所有属性,创建新对象时递归地复制所有子对象。需要注意处理循环引用的情况。

public static T DeepCopy<T>(T obj)
{
    if (obj == null) return default(T);

    Type type = obj.GetType();
    if (type.IsValueType || type == typeof(string))
    {
        return obj;
    }
    else 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(DeepCopy(array.GetValue(i)), i);
        }
        return (T)(object)copied;
    }

    object retVal = Activator.CreateInstance(type);
    FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    foreach (FieldInfo field in fields)
    {
        object fieldValue = field.GetValue(obj);
        if (fieldValue == null) continue;
        field.SetValue(retVal, DeepCopy(fieldValue));
    }
    return (T)retVal;
}
总结

浅拷贝和深拷贝是 C# 中一个非常重要的概念,了解它们的区别以及如何实现深拷贝可以帮助我们更好地处理对象的复制和引用问题。当我们需要在程序中复制对象或者传递对象时,需要仔细思考使用哪种拷贝方式,以避免出现不必要的问题。