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 просто хранит значение переданного массива, а не делает его полную копию. В этом случае, когда массив будет изменен, он будет изменен в обоих случаях.