Правильное копирование данных в C#

Я работаю над некоторым кодом моделирования в 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;

При этом * Точки являются экземплярами Точек, которые имеют несколько примитивных (двойных) и не примитивных (Вектор) типов данных.

Я сталкиваюсь с (очевидной) проблемой, заключающейся в том, что приведенный выше код, скорее всего, просто установит 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 ответа

Решение

Это одна из самых неприятных проблем с дизайном C# ИМХО.

Если 'Point' является структурой (значением), то будет сделана копия для каждого элемента, поэтому x = y сделает независимую копию у. Но если это класс (ссылка), x = y просто укажет ссылку x на то же хранилище, которое используется для y, так что они просто станут разными псевдонимами для одних и тех же данных.

Я знаю два решения вашей проблемы:

  • Используйте структуру. Это даст вам поведение типа значения, которое вы ожидаете от математических классов. Чтобы сохранить эффективность кода, вам, возможно, потребуется передавать ссылки везде, чтобы избежать непрерывного копирования структур.

  • Используйте класс, но будьте очень и очень осторожны при использовании =, чтобы убедиться, что вы сохраняете независимую копию данных. Вам нужно будет изменить x = y к чему-то другому, например x = new Point(y);,

Не могли бы вы использовать Clone(), а затем реализовать глубокое копирование, как вам это нужно?

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

Вы хотите пройти по ссылке. Ваши методы в настоящее время передаются по значению, что означает, что значения ваших переменных копируются. Метод всегда будет работать с копией данных.

Для перехода по ссылке сделайте следующее:

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);
Другие вопросы по тегам