【问题标题】:Properly copying data around in C#在 C# 中正确复制数据
【发布时间】:2011-01-20 06:31:07
【问题描述】:

我正在使用 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 是具有多种原始(双精度)和非原始(向量)数据类型的点的实例。

我遇到了一个(明显的)问题,上面的代码很可能只是将 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 
}

【问题讨论】:

  • 我假设 Point 是一个类,而不是一个结构?如果它的所有成员都是值类型,您是否考虑过将其也设为值类型?
  • @Bubbafat:我还有一些其他类只包含原语和 Vector(由原语组成)。如果我将所述类转换为 struct 以及 Vector,这是否允许我执行简单的深层复制而不是简单地使两个对象指向同一内存的分配?
  • 复制值类型总是会创建值类型的副本(与仅复制引用的引用类型相反)。在复制所有内容之前,您需要考虑这样做的其他影响(性能、装箱、内存、堆栈使用等),但如果这些类型是逻辑值类型而不是引用类型。

标签: c# deep-copy copying


【解决方案1】:

这是 C# 设计恕我直言的最严重的问题之一。

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

对于您的问题,我知道的两种解决方案是:

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

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

【讨论】:

    【解决方案2】:

    你能不能使用 Clone(),然后实现你需要的深拷贝?

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 只有当“Point”是一个值类型时才适用。 (OP 暗示它是一个类,而不是一个结构)。
      猜你喜欢
      • 2014-01-21
      • 1970-01-01
      • 2023-03-31
      • 2019-05-22
      • 2021-02-25
      • 2018-11-24
      • 1970-01-01
      • 2015-06-24
      • 2020-09-14
      相关资源
      最近更新 更多