开放的编程资料库

当前位置:我爱分享网 > C#教程 > 正文

C#浅拷贝和深拷贝

在本文中,我们比较了C#中对象的浅拷贝和深拷贝。

数据的复制是编程中的一项重要任务。对象是OOP中的复合数据类型。对象中的成员字段可以按值或按引用存储。可以通过两种方式执行复制。

浅拷贝将所有值和引用复制到一个新实例中。引用指向的数据不会被复制;只有指针被复制。新引用指向原始对象。对引用成员的任何更改都会影响这两个对象。

深拷贝将所有值复制到一个新实例中。对于存储为引用的成员,深拷贝执行被引用数据的深拷贝。创建引用对象的新副本。并存储指向新创建对象的指针。对这些引用对象的任何更改都不会影响该对象的其他副本。深拷贝是完全复制的对象。

如果成员字段是值类型,则对该字段进行逐位复制。如果该字段是引用类型,则复制引用但不复制引用对象;因此,原始对象中的引用和克隆中的引用指向同一个对象。

C#浅拷贝示例

以下程序执行浅拷贝。

namespace ShallowCopy;

class Color
{
    public int red;
    public int green;
    public int blue;

    public Color(int red, int green, int blue)
    {
        this.red = red;
        this.green = green;
        this.blue = blue;
    }
}

class MyObject : ICloneable
{
    public int id;
    public string size;
    public Color col;

    public MyObject(int id, string size, Color col)
    {
        this.id = id;
        this.size = size;
        this.col = col;
    }

    public object Clone()
    {
        return new MyObject(this.id, this.size, this.col);
    }

    public override string ToString()
    {
        var s = String.Format("id: {0}, size: {1}, color:({2}, {3}, {4})",
            this.id, this.size, this.col.red, this.col.green, this.col.blue);
        return s;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var col = new Color(23, 42, 223);
        var obj1 = new MyObject(23, "small", col);

        var obj2 = (MyObject)obj1.Clone();

        obj2.id += 1;
        obj2.size = "big";
        obj2.col.red = 255;

        Console.WriteLine(obj1);
        Console.WriteLine(obj2);
    }
}

这是一个浅拷贝的例子。我们定义了两个自定义对象:MyObjectColorMyObject对象将引用Color对象。

class MyObject : ICloneable

我们应该为我们要克隆的对象实现ICloneable接口。

public object Clone()
{
    return new MyObject(this.id, this.size, this.col);
}

ICloneable接口迫使我们创建一个Clone方法。此方法返回一个具有复制值的新对象。

var col = new Color(23, 42, 223);

我们创建Color对象的一个​​实例。

var obj1 = new MyObject(23, "small", col);

创建了MyObject类的实例。Color对象的实例被传递给构造函数。

var obj2 = (MyObject) obj1.Clone();

我们创建obj1对象的浅拷贝并将其分配给obj2变量。Clone方法返回一个Object,我们期望MyObject。这就是我们进行显式转换的原因。

obj2.id += 1;
obj2.size = "big";
obj2.col.red = 255;

这里我们修改复制对象的成员字段。我们增加id,将大小更改为“大”并更改颜色对象的红色部分。

Console.WriteLine(obj1);
Console.WriteLine(obj2);

Console.WriteLine方法调用obj2对象的ToString方法,返回对象的字符串表示形式。

$ dotnet run
id: 23, size: small, color:(255, 42, 223)
id: 24, size: big, color:(255, 42, 223)

我们可以看到ID不同(23对24)。尺寸不同(“小”与“大”)。但是颜色对象的红色部分对于两个实例(255)都是相同的。更改克隆对象的成员值(id、大小)不会影响原始对象。更改引用对象(col)的成员也影响了原始对象。换句话说,两个对象都引用内存中的同一个颜色对象。

C#深拷贝示例

为了改变这种行为,我们接下来进行深拷贝。

namespace DeepCopy;

class Color : ICloneable
{
    public int red;
    public int green;
    public int blue;

    public Color(int red, int green, int blue)
    {
        this.red = red;
        this.green = green;
        this.blue = blue;
    }

    public object Clone()
    {
        return new Color(this.red, this.green, this.blue);
    }
}

class MyObject : ICloneable
{
    public int id;
    public string size;
    public Color col;

    public MyObject(int id, string size, Color col)
    {
        this.id = id;
        this.size = size;
        this.col = col;
    }

    public object Clone()
    {
        return new MyObject(this.id, this.size,
            (Color)this.col.Clone());
    }

    public override string ToString()
    {
        var s = String.Format("id: {0}, size: {1}, color:({2}, {3}, {4})",
            this.id, this.size, this.col.red, this.col.green, this.col.blue);
        return s;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var col = new Color(23, 42, 223);
        var obj1 = new MyObject(23, "small", col);

        var obj2 = (MyObject)obj1.Clone();

        obj2.id += 1;
        obj2.size = "big";
        obj2.col.red = 255;

        Console.WriteLine(obj1);
        Console.WriteLine(obj2);
    }
}

在这个程序中,我们对对象执行深拷贝。

class Color : ICloneable

现在Color类实现了ICloneable接口。

public object Clone()
{
    return new Color(this.red, this.green, this.blue);
}

Color类也有一个Clone方法。这有助于创建引用对象的副本。

public object Clone()
{
    return new MyObject(this.id, this.size,
        (Color) this.col.Clone());
}

当我们克隆MyObject时,我们在col引用类型上调用Clone方法。这样我们也有一个颜色值的副本。

$ dotnet run
id: 23, size: small, color:(23, 42, 223)
id: 24, size: big, color:(255, 42, 223)

现在引用的Color对象的红色部分不一样了。原始对象保留了之前的值(23)。

在本文中,我们比较了C#中对象的浅拷贝和深拷贝。

列出所有C#教程。

未经允许不得转载:我爱分享网 » C#浅拷贝和深拷贝

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏