Search code examples
c#objectreferencestatemethod-parameters

C# - Object passed as method parameter changes state


I have a class Matrix with a 2d-array of values as a public property:

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

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

And I overloaded the *-Operator as a static method inside of 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;
    }

And I did following in my main-class:

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

The operator itself works fine, m2 is changed as intended. But m1 gets the same values as m2 after multiplication. I know that reference-types are passed as reference into a method, but I allocated a new object on the heap with the call "var resMatrix = new Matrix(m.Values);" right? Or does the compiler merge those two objects into one for performance-optimization? Is there a possibility to keep m1 the same just like value types, and if so, is it good and common practice?


Solution

  • As you know, Matrix is a reference type, so you made a new variable:

    var resMatrix = new Matrix(m.Values);
    

    However, double[,] is also a reference type! When you do this:

    Values = values;
    

    You are still making Values and values dependent on each other i.e. changing one's value will affect the other.

    To do this, you need to create a copy. One way to do this is Clone:

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