在C#中,原型模式是一种创建型设计模式,其核心思想是通过复制一个已有对象(原型)来创建新对象,而不是使用new重新初始化。这种方式在对象构造成本高或需要保持初始状态时非常有用。根据复制程度,克隆分为浅克隆和深克隆。

浅克隆的实现
C#中所有类都隐式继承自Object,而Object提供了受保护的MemberwiseClone方法,可以创建当前对象的浅副本。浅克隆会复制值类型字段,但引用类型字段只复制引用,不复制引用的对象本身。
using System;
public class Address
{
public string City { get; set; }
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
// 浅克隆:使用Object的MemberwiseClone
public Person ShallowClone()
{
return (Person)this.MemberwiseClone();
}
}
class Program
{
static void Main()
{
Person p1 = new Person
{
Name = "张三",
Age = 20,
Address = new Address { City = "北京" }
};
Person p2 = p1.ShallowClone();
p2.Name = "李四";
p2.Address.City = "上海";
// p1的Address.City也会变成上海,因为浅克隆共享引用
Console.WriteLine(p1.Address.City);
}
}
深克隆的实现
深克隆会递归复制所有引用类型的对象,使原对象与克隆对象完全独立。常见做法是手动编写克隆逻辑,或者通过序列化反序列化来实现。
手动深克隆
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
// 手动深克隆
public Person DeepClone()
{
return new Person
{
Name = this.Name,
Age = this.Age,
Address = new Address { City = this.Address.City }
};
}
}
通过序列化实现深克隆
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
public class Address
{
public string City { get; set; }
}
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
public Person DeepCloneBySerialize()
{
IFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
return (Person)formatter.Deserialize(stream);
}
}
}
使用ICloneable接口
C#提供了ICloneable接口,约定实现Clone方法。虽然该接口未区分深浅克隆,但我们可以在实现中明确指出行为。
using System;
public class User : ICloneable
{
public string Id { get; set; }
public int Score { get; set; }
public object Clone()
{
// 此处为浅克隆示例
return this.MemberwiseClone();
}
}
使用建议
- 如果对象只包含值类型或不可变引用类型,浅克隆通常足够。
- 当对象图较复杂且需要独立副本时,优先使用深克隆。
- 避免在Clone中调用构造函数逻辑,应保持克隆语义简单。
通过合理运用原型模式,C#开发者可以在合适的场景下减少重复构建逻辑,让对象创建更加灵活高效。