C#深拷贝方法探究及性能比较(多种深拷贝)

C#深拷贝方法探究及性能比较(多种深拷贝)

什么是深拷贝

在 C# 的开发中,经常需要复制一份对象,以便于对该对象进行修改而不影响原来的对象。浅拷贝(shallow copy)只是简单地复制了一份对象的引用,而不是实际的对象,原始对象和副本对象共享引用类型的成员变量。而深拷贝(deep copy)则会创建一份新的对象,并复制原始对象所有的成员变量,包括引用类型成员变量所引用的对象。

深拷贝的实现方式

1.手动实现

手动实现深拷贝的方法是通过递归复制所有被引用的对象及其属性。我们可以按照如下格式实现一个对象的深拷贝:

public class MyClass
{
    public int IntProperty { get; set; }
    public MySecondClass MySecondClassProperty { get; set; }

    public MyClass DeepCopy()
    {
        MyClass copy = new MyClass();
        copy.IntProperty = this.IntProperty;
        copy.MySecondClassProperty = new MySecondClass();
        copy.MySecondClassProperty.Property1 = this.MySecondClassProperty.Property1;
        copy.MySecondClassProperty.Property2 = this.MySecondClassProperty.Property2;
        copy.MySecondClassProperty.Property3 = this.MySecondClassProperty.Property3;
        return copy;
    }
}

public class MySecondClass
{
    public int Property1 { get; set; }
    public string Property2 { get; set; }
    public bool Property3 { get; set; }
}

虽然手动实现深拷贝比较繁琐,但是可以确保100%的拷贝结果正确,且运行速度比其他方法快一些。

2.使用序列化实现深拷贝

使用序列化实现深拷贝的方法是对被拷贝对象进行序列化和反序列化,实现对象的克隆。以下是使用BinaryFormatter实现对象的深拷贝的示例代码:

public static T DeepCopy<T>(T obj)
{
    using var stream = new MemoryStream();
    var formatter = new BinaryFormatter
    {
        Context = new StreamingContext(StreamingContextStates.Clone)
    };
    formatter.Serialize(stream, obj);
    stream.Seek(0, SeekOrigin.Begin);
    return (T)formatter.Deserialize(stream);
}

但是,使用序列化实现深拷贝的方法会对性能有一定的影响,并且不是所有对象都可以序列化。

3.使用反射实现深拷贝

使用反射实现深拷贝的方法是通过反射机制获取对象的类型信息,然后对其进行复制的操作。以下是使用反射实现对象的深拷贝的示例代码:

public static T DeepCopy<T>(T obj)
{
    if (obj == null)
    {
        return default(T);
    }

    var type = obj.GetType();
    if (!type.IsValueType && type != typeof(string))
    {
        object copy = Activator.CreateInstance(obj.GetType());
        foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
        {
            var fieldValue = field.GetValue(obj);
            if (fieldValue != null)
            {
                field.SetValue(copy, DeepCopy(fieldValue));
            }
        }

        foreach (PropertyInfo property in type.GetProperties())
        {
            if (property.CanRead && property.CanWrite && property.GetIndexParameters().Length == 0)
            {
                try
                {
                    var propertyValue = property.GetValue(obj, null);
                    if (propertyValue != null)
                    {
                        property.SetValue(copy, DeepCopy(propertyValue), null);
                    }
                }
                catch
                {
                    // Some indexers or properties may throw exception here, but I don’t care.
                }
            }
        }

        obj = (T)copy;
    }

    return obj;
}

深拷贝的性能比较

我们可以使用以下代码对三种深拷贝方法的性能进行比较:

var sourceObject = CreateLargeObjectGraph();
var stopwatch = Stopwatch.StartNew();

var copyByReflection = DeepCopyByReflection(sourceObject);
var reflectionTime = stopwatch.Elapsed;

stopwatch.Restart();

var copyBySerialization = DeepCopyBySerialization(sourceObject);
var serializationTime = stopwatch.Elapsed;

stopwatch.Restart();

var copyByManual = sourceObject.DeepCopy();
var manualTime = stopwatch.Elapsed;

其中,CreateLargeObjectGraph()方法用于创建一个包含1K个MyClass对象的对象图。

实验结果表明,手动实现深拷贝方法的速度最快,而基于序列化实现深拷贝的方法速度最慢。

示例说明

下面我们以一个Student类为例,演示如何使用各种深拷贝方法进行对象的拷贝。

public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
    public List<string> Courses { get; set; }

    public Student DeepCopy()
    {
        var copy = new Student();
        copy.Name = this.Name;
        copy.Age = this.Age;
        copy.Courses = new List<string>();
        foreach(var course in this.Courses)
        {
            copy.Courses.Add(course);
        }
        return copy;
    }
}

使用手动实现深拷贝方法:

var student1 = new Student() { Name = "Tom", Age = 18, Courses = new List<string>() { "Math", "English" } };
var student2 = student1.DeepCopy();
student1.Name = "Jerry";
student1.Age = 19;
student1.Courses.Add("History");
Console.WriteLine(student1.Name + " " + student1.Age + " " + string.Join(",", student1.Courses));
Console.WriteLine(student2.Name + " " + student2.Age + " " + string.Join(",", student2.Courses));

运行以上代码,输出:

Jerry 19 Math,English,History
Tom 18 Math,English

使用BinaryFormatter实现深拷贝方法:

var student1 = new Student() { Name = "Tom", Age = 18, Courses = new List<string>() { "Math", "English" } };
var student2 = DeepCopyBySerialization(student1);
student1.Name = "Jerry";
student1.Age = 19;
student1.Courses.Add("History");
Console.WriteLine(student1.Name + " " + student1.Age + " " + string.Join(",", student1.Courses));
Console.WriteLine(student2.Name + " " + student2.Age + " " + string.Join(",", student2.Courses));

使用反射实现深拷贝方法:

var student1 = new Student() { Name = "Tom", Age = 18, Courses = new List<string>() { "Math", "English" } };
var student2 = DeepCopyByReflection(student1);
student1.Name = "Jerry";
student1.Age = 19;
student1.Courses.Add("History");
Console.WriteLine(student1.Name + " " + student1.Age + " " + string.Join(",", student1.Courses));
Console.WriteLine(student2.Name + " " + student2.Age + " " + string.Join(",", student2.Courses));

以上这些示例可以帮助我们理解三种深拷贝方法的实现过程,并在实际开发中提供参考。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#深拷贝方法探究及性能比较(多种深拷贝) - Python技术站

(0)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • Asp.net core利用IIS在windows上进行托管步骤详解

    ASP.NET Core 利用 IIS 在 Windows 上进行托管步骤详解 在 Windows 上,可以使用 IIS(Internet Information Services)来托管 ASP.NET Core 应用程序。本攻略将详细讲解 ASP.NET Core 利用 IIS 在 Windows 上进行托管的步骤。 1. 安装 .NET Core Ho…

    C# 2023年5月17日
    00
  • C# EF Core可视化工具的使用及EF Core入门语句操作代码

    让我来详细讲解一下 “C# EF Core可视化工具的使用及EF Core入门语句操作代码” 的完整攻略。 EF Core简介 EF(Core)是一个轻量级的ORM框架,它的主要功能是将对象模型映射到关系数据库中,以及从数据库中获取和存储数据。 EF Core可视化工具的使用 EF Core可视化工具可以方便地管理 EF Core 的各种功能,比如数据库迁移…

    C# 2023年6月3日
    00
  • C# Winform自动更新程序实例详解

    C# WinForm自动更新程序实例详解 引言 随着软件的不断发展,软件版本的迭代更新也变得越来越频繁。在软件的运行过程中,我们经常需要通过网站或者其他方式来更新软件。如何在WinForm应用程序中实现自动更新,是值得研究的一个问题。 本文将介绍如何使用C# WinForm实现自动更新程序。通过本文的学习,您将能够掌握WinForm自动更新程序的开发原理和实…

    C# 2023年6月1日
    00
  • 在asp.net中使用加密数据库联接字符串保证数据安全

    在ASP.NET中,可以使用加密数据库连接字符串的方式来保障数据库的安全性。具体步骤如下: 1. 生成加密密钥 在ASP.NET中,可以使用System.Web.Security中的方法生成一个加密密钥。在Global.asax.cs中添加以下代码: void Application_Start(object sender, EventArgs e) { /…

    C# 2023年5月31日
    00
  • .NET Framework各版本(.NET2.0 3.0 3.5 4.0)区别

    下面是关于“.NET Framework各版本(.NET 2.0、3.0、3.5、4.0)区别”的完整攻略,包含两个示例。 1. .NET Framework各版本区别 .NET Framework是一个由Microsoft开发的应用程序框架,用于在Windows操作系统上开发和运行各种类型的应用程序。下面是.NET Framework各版本的区别: .NE…

    C# 2023年5月15日
    00
  • C#算法之大牛生小牛的问题高效解决方法

    C#算法之大牛生小牛的问题高效解决方法 问题描述 题目来源于 LeetCode,现在有一只大牛和一只小牛,它们的初始体重分别为 $x$ 和 $y$,每年它们的体重都会增加固定的比例(比例为 $p$),求当小牛的体重超过大牛的体重时,需要多少年。 解题思路 考虑使用循环解决。 每年大牛的体重增加 $p$%,小牛的体重增加 $2p$%,那么循环条件可以设为小牛体…

    C# 2023年6月7日
    00
  • 在C#中如何使用Dapper详解(译)

    以下是关于“在C#中如何使用 Dapper”的详细攻略: 1. 什么是 Dapper? Dapper 是一个简单、轻量级的 .NET ORM 框架,与其他相似的框架相比,它的性能更高、更稳定,支持多种数据库,包括 SQL Server、MySQL、PostgreSQL 等。 2. 如何使用 Dapper? 首先,我们需要安装 Dapper,可以通过 NuGe…

    C# 2023年5月31日
    00
  • 基于C#制作一个飞机大战小游戏的全过程

    下面将详细讲解如何基于C#制作一个飞机大战小游戏的全过程。 第一步:游戏的框架搭建 在C#开发环境中新建一个空白项目,然后添加游戏画面的素材图片和背景音乐。接下来,我们需要编写游戏框架,包括游戏主循环和绘制游戏画面的代码。以下是一段示例代码: // 定义游戏主窗口 public class MainWindow : Form { // 定义画面控件 priv…

    C# 2023年6月7日
    00
合作推广
合作推广
分享本页
返回顶部