在C#编程中,对象的拷贝操作分为深拷贝和浅拷贝两种类型,两者的核心差异在于对引用类型字段的处理方式不同,开发者需要根据实际业务场景选择合适的拷贝方式。浅拷贝仅复制对象的值类型字段,对于引用类型字段只复制其引用地址,拷贝后的新对象和原对象会共享同一个引用类型实例。深拷贝则会完整复制对象的所有字段,包括引用类型指向的实例,拷贝后的新对象和原对象完全独立,修改任意一个对象都不会影响另一个对象。

浅拷贝的实现方法
使用Object类的MemberwiseClone方法
所有C#类都继承自Object类,Object类提供了MemberwiseClone方法,该方法可以创建当前对象的浅表副本,是实现浅拷贝最简单的方式。
using System;
namespace CloneDemo
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Address AddressInfo { get; set; }
// 实现浅拷贝的方法
public Person ShallowClone()
{
// MemberwiseClone是受保护方法,只能在类内部调用
return (Person)this.MemberwiseClone();
}
}
public class Address
{
public string City { get; set; }
public string Street { get; set; }
}
class Program
{
static void Main(string[] args)
{
Person original = new Person
{
Name = "张三",
Age = 25,
AddressInfo = new Address { City = "北京", Street = "朝阳路" }
};
// 执行浅拷贝
Person shallowCopy = original.ShallowClone();
// 修改拷贝对象的引用类型字段
shallowCopy.AddressInfo.City = "上海";
Console.WriteLine($"原对象城市:{original.AddressInfo.City}");
Console.WriteLine($"拷贝对象城市:{shallowCopy.AddressInfo.City}");
}
}
}
上述代码中,修改浅拷贝对象的AddressInfo的City属性后,原对象的对应属性也被修改了,说明两个对象共享同一个Address实例。
实现ICloneable接口
C#提供了ICloneable接口,该接口定义了Clone方法,我们可以让类实现这个接口,在Clone方法中调用MemberwiseClone实现浅拷贝,这种方式更符合C#的接口规范。
using System;
namespace CloneDemo
{
public class Student : ICloneable
{
public string StudentName { get; set; }
public int Score { get; set; }
public ClassInfo Class { get; set; }
// 实现ICloneable接口的Clone方法,返回浅拷贝对象
public object Clone()
{
return this.MemberwiseClone();
}
}
public class ClassInfo
{
public string ClassName { get; set; }
public int ClassId { get; set; }
}
}
深拷贝的实现方法
手动逐字段赋值
对于结构简单的类,我们可以手动为每个字段赋值,引用类型字段创建新的实例并复制其属性值,这种方式最直观,但是当类的字段较多或者嵌套层级较深时,代码会非常繁琐。
using System;
namespace CloneDemo
{
public class User
{
public string UserName { get; set; }
public int UserAge { get; set; }
public ContactInfo Contact { get; set; }
// 手动实现深拷贝
public User DeepClone()
{
User newUser = new User
{
UserName = this.UserName,
UserAge = this.UserAge,
// 为引用类型创建新实例,复制属性值
Contact = new ContactInfo
{
Phone = this.Contact.Phone,
Email = this.Contact.Email
}
};
return newUser;
}
}
public class ContactInfo
{
public string Phone { get; set; }
public string Email { get; set; }
}
class Program
{
static void Main(string[] args)
{
User originalUser = new User
{
UserName = "李四",
UserAge = 30,
Contact = new ContactInfo { Phone = "13800138000", Email = "test@ipipp.com" }
};
User deepCopyUser = originalUser.DeepClone();
deepCopyUser.Contact.Phone = "13900139000";
Console.WriteLine($"原用户手机号:{originalUser.Contact.Phone}");
Console.WriteLine($"深拷贝用户手机号:{deepCopyUser.Contact.Phone}");
}
}
}
上述代码中,修改深拷贝对象的Contact属性后,原对象的Contact属性没有变化,说明两个对象的引用类型字段是完全独立的。
使用序列化实现深拷贝
我们可以利用C#的序列化机制,将对象序列化为字节流,再将字节流反序列化为新的对象,这种方式可以自动处理所有层级的引用类型,不需要手动编写赋值代码,适合嵌套层级复杂的对象,但是性能会比手动赋值稍差。
需要注意,要使用这种方式,类必须标记为[Serializable]特性。
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace CloneDemo
{
[Serializable]
public class Department
{
public string DeptName { get; set; }
public Employee Manager { get; set; }
}
[Serializable]
public class Employee
{
public string EmpName { get; set; }
public int EmpId { get; set; }
}
public static class DeepCloneHelper
{
// 使用二进制序列化实现深拷贝的通用方法
public static T DeepClone<T>(T obj)
{
if (obj == null)
{
return default(T);
}
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
// 序列化对象到内存流
formatter.Serialize(stream, obj);
// 重置流的位置
stream.Seek(0, SeekOrigin.Begin);
// 反序列化为新对象
return (T)formatter.Deserialize(stream);
}
}
}
class Program
{
static void Main(string[] args)
{
Department originalDept = new Department
{
DeptName = "研发部",
Manager = new Employee { EmpName = "王五", EmpId = 1001 }
};
Department deepCloneDept = DeepCloneHelper.DeepClone(originalDept);
deepCloneDept.Manager.EmpName = "赵六";
Console.WriteLine($"原部门经理:{originalDept.Manager.EmpName}");
Console.WriteLine($"深拷贝部门经理:{deepCloneDept.Manager.EmpName}");
}
}
}
使用表达式树实现通用深拷贝
表达式树可以在运行时动态生成拷贝代码,兼顾性能和通用性,适合需要频繁进行深拷贝操作的场景,我们可以编写一个通用的深拷贝扩展方法,适配不同类型的对象。
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace CloneDemo
{
public class Order
{
public int OrderId { get; set; }
public string OrderNo { get; set; }
public List<OrderItem> Items { get; set; }
}
public class OrderItem
{
public string ProductName { get; set; }
public int Quantity { get; set; }
}
public static class ExpressionDeepCloneHelper
{
// 缓存表达式树编译后的委托,避免重复编译提升性能
private static readonly Dictionary<Type, Func<object, object>> CloneCache = new Dictionary<Type, Func<object, object>>();
public static T DeepClone<T>(this T obj) where T : class
{
if (obj == null)
{
return null;
}
Type type = typeof(T);
if (!CloneCache.ContainsKey(type))
{
// 构建表达式树生成拷贝逻辑
var parameter = Expression.Parameter(typeof(object), "input");
var castInput = Expression.Convert(parameter, type);
var newExpr = Expression.New(type);
var properties = type.GetProperties();
var bindings = new List<MemberBinding>();
foreach (var prop in properties)
{
if (prop.CanRead && prop.CanWrite)
{
var propExpr = Expression.Property(castInput, prop);
// 这里简化逻辑,实际需要根据属性类型判断是否递归深拷贝
var binding = Expression.Bind(prop, propExpr);
bindings.Add(binding);
}
}
var memberInit = Expression.MemberInit(newExpr, bindings);
var lambda = Expression.Lambda<Func<object, object>>(Expression.Convert(memberInit, typeof(object)), parameter);
CloneCache[type] = lambda.Compile();
}
return (T)CloneCache[type](obj);
}
}
}
两种拷贝方式的选择建议
如果只需要复制对象的值类型字段,或者引用类型字段不会被修改,优先选择浅拷贝,实现简单性能更高。如果需要完全独立的对象,修改拷贝对象不会影响原对象,就必须使用深拷贝。对于简单的类可以手动实现深拷贝,对于复杂的嵌套类可以使用序列化或者表达式树的方式实现,减少重复代码。
C#深拷贝浅拷贝ICloneableObject_MemberwiseClone修改时间:2026-07-16 01:54:36