unity C#深拷贝、浅拷贝、直接赋值区别与经典实例

发布时间:2024年01月13日


在C#中,浅拷贝(Shallow Copy)和深拷贝(Deep Copy)是两种不同级别的对象复制方式。它们的区别主要体现在处理引用类型字段时的行为。

浅拷贝

浅拷贝是指复制对象时,只复制对象本身所包含的值类型字段,并将引用类型字段简单地复制一份引用,而不是复制引用的对象内容。这意味着新旧对象中的引用类型字段指向相同的内存地址。因此,对任何一方引用类型的字段做出修改都会影响到另一个对象。

举例说明:

class Person
{
    public string Name { get; set; } // 值类型属性,字符串实际上是引用类型,但在此处作为不可变对象讨论
    public Car CarOwned { get; set; } // 引用类型属性
}

class Car
{
    public string Brand { get; set; }
}

// 创建原始对象
var originalPerson = new Person { Name = "Alice", CarOwned = new Car { Brand = "Toyota" } };
var shallowCopyPerson = originalPerson.MemberwiseClone(); // 使用默认的浅拷贝方法

// 修改浅拷贝后的引用类型字段
shallowCopyPerson.CarOwned.Brand = "Ford";

// 输出结果会显示两个对象的CarOwned.Brand都为"Frod"
Console.WriteLine(originalPerson.CarOwned.Brand); // 输出 "Ford"
Console.WriteLine(shallowCopyPerson.CarOwned.Brand); // 输出 "Ford"

在这个例子中,MemberwiseClone() 方法执行了浅拷贝操作,虽然 Person 对象被复制了一份,但 CarOwned 这个引用类型的字段并没有创建新的 Car 实例,而是共享了同一个实例。

深拷贝

深拷贝则不仅复制值类型字段,还复制引用类型字段所引用的对象,并为这些对象分配新的内存空间。这样一来,修改深拷贝后对象的引用类型字段不会影响到原对象。

深拷贝需要程序员自定义实现,通常涉及到递归遍历所有引用类型字段并逐一复制其内容。例如:

class Person
{
    public string Name { get; set; }
    public Car CarOwned { get; set; }

    // 自定义深拷贝方法
    public Person DeepCopy()
    {
        var copy = (Person)this.MemberwiseClone();
        if (this.CarOwned != null)
            copy.CarOwned = new Car { Brand = this.CarOwned.Brand }; // 深拷贝Car对象

        return copy;
    }
}

class Car
{
    public string Brand { get; set; }
}

// 创建原始对象
var originalPerson = new Person { Name = "Alice", CarOwned = new Car { Brand = "Toyota" } };
var deepCopyPerson = originalPerson.DeepCopy();

// 修改深拷贝后的引用类型字段
deepCopyPerson.CarOwned.Brand = "Ford";

// 输出结果会显示原对象的CarOwned.Brand仍然是"Toyota"
Console.WriteLine(originalPerson.CarOwned.Brand); // 输出 "Toyota"
Console.WriteLine(deepCopyPerson.CarOwned.Brand); // 输出 "Ford"

在上述深拷贝示例中,DeepCopy() 方法手动创建了 Car 类的新实例,这样 originalPersondeepCopyPerson 就拥有各自独立的 Car 对象,修改其中一个不会影响另一个。

浅拷贝和直接赋值有啥区别

浅拷贝(Shallow Copy)和直接赋值在处理引用类型变量时,其实是有相似之处的,但也有微妙的区别:

直接赋值:
当一个对象被直接赋值给另一个变量时,实际上创建的是原对象的一个引用副本。这意味着新变量和原变量都指向同一个内存地址,对于值类型而言,效果等同于复制了实际数据;而对于引用类型,只是复制了对原始对象的引用。

例如,在C#中:

class MyClass
{
    public string Value;
}

MyClass obj1 = new MyClass { Value = "Hello" };
MyClass obj2 = obj1; // 直接赋值

obj2.Value = "World"; // 改变 obj2 的 Value 属性

在此例中,obj2obj1 的引用副本,所以改变 obj2.Value 会导致 obj1.Value 同样变为 “World”,因为它们共享同一份引用类型的内部状态。

浅拷贝:
浅拷贝同样是创建了一个新的对象,并且复制了原对象的所有非引用类型字段值和引用类型的引用。与直接赋值类似,浅拷贝后的引用类型成员仍然指向原来的引用类型的实例。

例如,使用C#中的 MemberwiseClone() 方法进行浅拷贝:

class MyClass
{
    public string Value;
    public AnotherClass ReferenceTypeField;

    public MyClass ShallowCopy()
    {
        return (MyClass)this.MemberwiseClone();
    }
}

class AnotherClass { /* ... */ }

MyClass obj1 = new MyClass { Value = "Hello", ReferenceTypeField = new AnotherClass() };
MyClass obj3 = obj1.ShallowCopy(); // 浅拷贝

obj3.Value = "World"; // 改变 obj3 的 Value 属性
obj3.ReferenceTypeField.SomeProperty = "New Value"; // 改变引用类型字段属性

// 这里,obj1.Value 不受影响,但 obj1.ReferenceTypeField.SomeProperty 会被修改

在这个例子中,虽然 obj3obj1 的浅拷贝,改变了 obj3.Value 并不影响 obj1.Value,因为这里 Value 是值类型(字符串在.NET中是不可变类型)。然而,ReferenceTypeFieldobj1obj3 中指向的是同一个 AnotherClass 实例,因此更改 obj3.ReferenceTypeField 的属性会影响到 obj1.ReferenceTypeField

总结:

  • 直接赋值:简单地将源对象的引用传递给目标变量,两者指向相同的内存地址。
  • 浅拷贝:创建了一个新对象,其值类型字段拥有独立的副本,而引用类型字段依然指向原有对象的引用,即不创建引用类型内部状态的新副本。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

?最后我们放松一下眼睛
在这里插入图片描述

文章来源:https://blog.csdn.net/qqrrjj2011/article/details/135567705
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。