C# - Объект передан как параметр метода изменяет состояние

У меня есть класс Matrix с 2d-массивом значений в качестве открытого свойства:

public class Matrix
{
    public double[,] Values { get; set; }

    public Matrix(double[,] values)
    {
        Values = values;
    }
    ...
}

И я перегрузил *-оператор как статический метод внутри Matrix:

    public static Matrix operator *(Matrix m, double operand)
    {
        var resMatrix = new Matrix(m.Values);
        for (var i = 0; i < resMatrix.Values.GetLength(0); i++)
        {
            for (var j = 0; j < resMatrix.Values.GetLength(1); j++)
            {
                resMatrix[i, j] *= operand;
            }
        }
        return resMatrix;
    }

И я сделал следующее в моем основном классе:

internal class Program
{
    public static void Main(string[] args)
    {
        var m1 = new Matrix(new double[,]
        {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        });
        Console.WriteLine(m1);

        var m2 = m1 * 2;

        Console.WriteLine(m2);
        Console.WriteLine(m1);
    }
}

Сам оператор работает нормально, м2 меняется по назначению. Но m1 получает те же значения, что и m2 после умножения. Я знаю, что ссылочные типы передаются в качестве ссылки в метод, но я выделил новый объект в куче с помощью вызова "var resMatrix = new Matrix(m.Values);" право? Или компилятор объединяет эти два объекта в один для оптимизации производительности? Есть ли возможность оставить m1 таким же, как и у типов значений, и если да, то это хорошая и распространенная практика?

2 ответа

Решение

Как Вам известно, Matrix является ссылочным типом, поэтому вы создали новую переменную:

var resMatrix = new Matrix(m.Values);

Тем не мение, double[,] это также ссылочный тип! Когда вы делаете это:

Values = values;

Вы все еще делаете Values а также values зависит друг от друга, т.е. изменение одного значения повлияет на другого.

Для этого вам нужно создать копию. Один из способов сделать это Clone:

Values = values.Clone() as double[,];

Я подозреваю, что ваш конструктор Matrix просто хранит значение переданного массива, а не делает его полную копию. В этом случае, когда массив будет изменен, он будет изменен в обоих случаях.

Другие вопросы по тегам