下面我将详细介绍一下 "C#浅拷贝和深拷贝实例解析" 的完整攻略。
一、浅拷贝和深拷贝的概念
在 C# 中,对象的拷贝方式有两种:浅拷贝和深拷贝。浅拷贝只是复制对象的引用,而不复制引用对象本身;深拷贝则是复制所有的引用对象。
二、浅拷贝和深拷贝的实现
1. 实现浅拷贝
在 C# 中,想要实现对象的浅拷贝,我们可以在该对象中添加一个 Clone() 方法。在 Clone() 方法中,我们只需要创建一个新的对象,并将原对象中所有的值类型成员复制给新对象,但对于引用类型的成员,我们只需要复制它们的引用即可。
接下来是一个浅拷贝示例:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
public Person Clone()
{
return (Person)this.MemberwiseClone();
}
}
class Address
{
public string City { get; set; }
public string Street { get; set; }
}
// 测试用例
Person person1 = new Person
{
Name = "张三",
Age = 18,
Address = new Address { City = "北京", Street = "海淀区" }
};
Person person2 = person1.Clone();
person2.Address.City = "上海";
Console.WriteLine(person1.Address.City); // 输出:上海
从上面的代码中可以看出,我们在 Person 类中添加了一个 Clone() 方法,而在这个方法中,我们调用了 Object 类的 MemberwiseClone() 方法,它能够创建一个当前对象的浅表副本。在该示例中,person1 和 person2 对象都拥有自己的地址引用,但这些引用指向的是同一个 Address 对象。所以当我们更新 person2.Address.City,实际上也会更新 person1.Address.City。
2. 实现深拷贝
那么如果我们想要实现深拷贝呢?在 C# 中,实现深拷贝的方式基本上有两种:手动拷贝和序列化。
手动实现深拷贝的方式是比较基础的。我们需要在创建新的对象时,对于引用类型的成员,我们需要递归每一个成员,依次创建新的对象并赋值。下面是一个手动实现深拷贝的示例:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
public Person Clone()
{
Address address = new Address { City = this.Address.City, Street = this.Address.Street };
return new Person { Name = this.Name, Age = this.Age, Address = address };
}
}
class Address
{
public string City { get; set; }
public string Street { get; set; }
}
// 测试用例
Person person1 = new Person
{
Name = "张三",
Age = 18,
Address = new Address { City = "北京", Street = "海淀区" }
};
Person person2 = person1.Clone();
person2.Address.City = "上海";
Console.WriteLine(person1.Address.City); // 输出:北京
从上面的代码中可以看出,我们在 Person 类中手动实现了 Clone() 方法。在这个方法中,我们递归的复制了每一个成员,生成了一个全新的对象。
当然,手动实现深拷贝是比较麻烦的,我们也可以使用 .NET 中的序列化和反序列化来实现深拷贝。我们只需要将携带了数据的对象序列化成二进制格式,再反序列化出新的对象即可实现深拷贝。下面是一个使用序列化实现深拷贝的示例:
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
public Person Clone()
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, this);
stream.Position = 0;
return (Person)formatter.Deserialize(stream);
}
}
class Address
{
public string City { get; set; }
public string Street { get; set; }
}
// 测试用例
Person person1 = new Person
{
Name = "张三",
Age = 18,
Address = new Address { City = "北京", Street = "海淀区" }
};
Person person2 = person1.Clone();
person2.Address.City = "上海";
Console.WriteLine(person1.Address.City); // 输出:北京
从上面的代码中可以看出,我们在 Person 类中使用了 .NET 中的序列化和反序列化方法,先将 person1 对象序列化到一个内存流中,然后再从内存流中反序列化出 person2 对象。由于序列化和反序列化的过程都将创建新的对象,所以 person1 和 person2 对象拥有自己的地址引用,互不干扰。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#浅拷贝和深拷贝实例解析 - Python技术站