在C#中创建结构的浅表副本

问题描述 投票:1回答:4

我试图搜索我的答案,并发现了有关C而不是C#的答案,所以想到了发布它。

我的问题在这里可能微不足道。

根据我的理解(简单来说)

复制完成后

浅复制->主对象和复制对象(引用或值类型)应指向内存中的同一对象

DeepCopy->主对象和复制对象(引用或值类型)应指向内存中的不同对象

继续进行,我在C#中有一个结构,并试图对其进行浅表复制。我尝试使用“ MemberwiseClone”方法,但我猜它仅适用于引用类型。对于值类型,我认为“ MemberwiseClone”方法会将其装箱到一个对象中,然后将其装箱到堆栈中的另一个内存地址中。

我尝试过的如下。

我的问题是,如何(尽可能)创建简单结构的浅表副本?

我希望我的基本原理是正确的,不要讲垃圾。如果我所作的任何陈述有误,请纠正我。

问候,

Samar

struct MyStruct : ICloneable
{
    public int MyProperty { get; set; }

    public object Clone()
    {
        return this.MemberwiseClone();//boxing into object
    }
}


    private void btnChkStr_Click(object sender, EventArgs e)
    {
        MyStruct struct1 = new MyStruct();
        struct1.MyProperty = 1;

        //MyStruct struct2 = struct1; //This will create a deep copy
        MyStruct struct2 = (MyStruct)(struct1.Clone());//unboxing into structure hence allocating a different memory address
        struct2.MyProperty = 2;

        MessageBox.Show(struct1.MyProperty.ToString()); //still showing 1
    }
c# .net clone deep-copy shallow-copy
4个回答
5
投票

您对深层副本与浅层副本的期望不正确。浅表副本将复制所有值类型,并且仅复制引用类型的引用。深层副本将复制所有值类型和所有引用类型。

因此您的结构在执行时已经执行了浅表复制:

MyStruct struct2 = struct1;

此代码示例(控制台应用程序显示,更改第二个结构中的对象的值也会更改第一个结构中的对象的值,因为该对象刚刚被引用复制:

class Program
{
    static void Main(string[] args)
    {
        Test t1 = new Test();
        t1.i = 1;
        t1.o = new Klasse();
        t1.o.i = 1;

        Test t2 = t1;
        t2.i = 2;
        t2.o.i = 2;

        Console.WriteLine(t1.i.ToString());
        Console.WriteLine(t1.o.i.ToString());
        Console.WriteLine(t2.i.ToString());
        Console.WriteLine(t2.o.i.ToString());
        Console.Read();
    }
}

struct Test
{
    public int i;
    public Klasse o;
}

class Klasse
{
    public int i = 0;
}

2
投票

您对浅表副本的定义可以通过将框显式装箱来实现。但是,由于该结构是盒装的,因此访问它的属性并不容易!

void Main()
{
    object o1 = new M { A = 1 };
    object o2 = o1;

    // o2.A = 100 (this can also be done using dynamic)
    var prop = typeof(M).GetProperty("A");
    prop.SetValue(o2, 100);

    // prints 100, since both point to the same instance
    Console.WriteLine(((M)o1).A);
}

public struct M {
    public int A { get; set; }
}

通常,尽管将结构分配给新变量(或调用MemberwiseClone(),但将复制该结构的所有字段。

还应注意,您对深层和浅层副本的定义与通常使用的定义不同。一般而言:

[浅拷贝:创建了该对象的新实例,因此其所有成员都通过引用被复制(例如,a.X和shallowCopyOfA.X仍将引用同一对象)。值类型的成员(例如结构和基元)按值复制。

深层复制:创建对象的新实例,并且所有成员也被深层复制。


1
投票

不确定您对“副本”的要求。如在其他地方提到的,结构在分配或传递给方法时已按值复制。因此,也许您不需要额外的费用?

也许这仅仅是您想要的(不确定它是否对任何事情都有用!):

struct MyStruct : ICloneable
{
    public int MyProperty { get; set; }

    public MyStruct Clone()
    {
        return this;
    }
    object ICloneable.Clone()
    {
        return Clone();
    }
}

警告语:您的MyStruct是所谓的mutable结构,因为自动属性的set访问器是公共的。许多人认为可变结构是“邪恶的”,因为值类型语义和可变性的结合会导致令人惊讶的行为。

EDIT:如果要按引用复制语义,为什么要首先使用struct而不是class?像类一样,结构不是对对象位置的引用。正如其他人给出的示例一样,将MyStruct装箱到object变量中将使object成为对包含MyStruct值的box的引用。对该框的引用可以通过引用复制。

您可以创建一个仅包含MyStruct类型的实例字段的类。然后,该类将您的结构“包装”为引用类型,并且您可以通过通常的引用类型语义来复制此类的实例(复制引用,不复制对象本身)。


0
投票

不可能对结构进行如此浅的复制。

考虑使用类。

© www.soinside.com 2019 - 2024. All rights reserved.