在C#中正确复制数据

时间:2011-01-20 06:31:08

标签: c# deep-copy copying

我正在使用C#中的一些模拟代码,我有一些代码:

public void predict(Point start, Point end)
{
    end.velocity = start.velocity + dt * end.acceleration;
    end.position = start.position + dt * end.velocity;
}

其中位置,速度,加速度是我用相关运算符定义的一些矢量数据类型。

以及我正在做的代码:

StartPoint = EndPoint;
EndPoint = CurrentPoint;

* Points是具有多个原始(双)和非原始(Vector)数据类型的Point的实例。

我遇到上述代码的(显而易见的)问题,很可能只是将StartPoint设置为指向以前EndPoint的数据,而EndPoint将指向CurrentPoint。

意思是,如果我再次修改CurrentPoint,我最终会意外修改EndPoint。

在C ++中,这很容易防止,因为我可以定义我的赋值运算符来对我的Point对象中的底层数据进行深层复制。如何在C#中阻止这种情况?

感谢您的帮助!

编辑:Vector类定义为

[Serializable]
public class Vector
{
    private Double[] data = new Double[Constants.Dimensions];

    ... snip ...

    public static Vector operator +(Vector lhs, Vector rhs)
    {
        Vector result = new Vector();
        for (UInt32 i = 0; i < Constants.dimensions; i++)
            result[i] = lhs[i] + rhs[i];
        return result;
    }

    lots more code here 
}

3 个答案:

答案 0 :(得分:2)

这是C#设计恕我直言中最糟糕的问题之一。

如果'Point'是结构(值),则会生成成员副本,因此x = y将创建y的独立副本。但如果它是一个类(引用),x = y将简单地将引用x指向用于y的相同存储,因此这两个将简单地变为相同数据的不同“别名”。

我知道的两个解决方案是:

  • 使用结构。这将为您提供数学类所期望的值类型行为。为了保持代码的有效性,您可能需要在任何地方通过引用来避免结构被不断复制。

  • 使用类,但在使用=时要非常小心,以确保保留数据的独立副本。您需要将x = y更改为其他内容,例如: x = new Point(y);

答案 1 :(得分:0)

您可以使用Clone(),然后根据需要实现深层复制吗?

StartPoint = EndPoint; 
EndPoint = (Point)CurrentPoint.Clone(); 

答案 2 :(得分:0)

您希望通过引用传递。您的方法当前正在按值传递,这意味着正在复制变量的值。该方法将始终使用数据副本。

要通过引用传递,请执行以下操作:

public void predict(ref Point start, ref Point end)
{
    end.velocity = start.velocity + dt * end.acceleration;
    end.position = start.position + dt * end.velocity;
}

然后您必须使用ref关键字调用该方法,如下所示:

predict(ref start, ref end);