C#如何实现深拷贝和浅拷贝?有哪些常用的实现方法

来源:3D模型作者:狼行天下头衔:草根站长
导读:本期聚焦于小伙伴创作的《C#如何实现深拷贝和浅拷贝?有哪些常用的实现方法》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何实现深拷贝和浅拷贝?有哪些常用的实现方法》有用,将其分享出去将是对创作者最好的鼓励。

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

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}");
        }
    }
}

上述代码中,修改浅拷贝对象的AddressInfoCity属性后,原对象的对应属性也被修改了,说明两个对象共享同一个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

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。