文章目录
- 浅拷贝
- 深拷贝
- 浅拷贝和直接赋值有啥区别
在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
类的新实例,这样 originalPerson
和 deepCopyPerson
就拥有各自独立的 Car
对象,修改其中一个不会影响另一个。
浅拷贝和直接赋值有啥区别
浅拷贝(Shallow Copy)和直接赋值在处理引用类型变量时,其实是有相似之处的,但也有微妙的区别:
直接赋值:
当一个对象被直接赋值给另一个变量时,实际上创建的是原对象的一个引用副本。这意味着新变量和原变量都指向同一个内存地址,对于值类型而言,效果等同于复制了实际数据;而对于引用类型,只是复制了对原始对象的引用。
例如,在C#中:
class MyClass
{public string Value;
}MyClass obj1 = new MyClass { Value = "Hello" };
MyClass obj2 = obj1; // 直接赋值obj2.Value = "World"; // 改变 obj2 的 Value 属性
在此例中,obj2
是 obj1
的引用副本,所以改变 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 会被修改
在这个例子中,虽然 obj3
是 obj1
的浅拷贝,改变了 obj3.Value
并不影响 obj1.Value
,因为这里 Value
是值类型(字符串在.NET中是不可变类型)。然而,ReferenceTypeField
在 obj1
和 obj3
中指向的是同一个 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)
————————————————
最后我们放松一下眼睛