Home > .Net > A problem with using static member in a class C#.NET

A problem with using static member in a class C#.NET

Today, I would like to tell about some bug I had in my C#.NET code, and a simple way to fix it.

When needed a transform matrix 3 x 3, I wrote a simple class Matrix3X3; this class includes static feilds “Zero” and “Ones” for Zero-Matrix and Ones-Matrix appropriately.
Let’s take a brief look of the implementation:

class Matrix3X3
{
        public static Matrix3X3 Zero = new Matrix3X3(0);
        public static Matrix3X3 Ones = new Matrix3X3(1);

        // class members ...

        public Matrix3X3(double value)
        {
                // Fill the whole matrix with same value.
                // ...
        }

        // class methods ...
}

Those static feilds are very convenient: they let me do quick matrix inline initialization, rather then iterating over all matrix’s members. There are hundreds of matrices in the code; each one gets some content by using next simple construction:

public void SomeFunction(out Matrix3X3 matrix)
{
        matrix = Matrix3X3.Ones;

        if (m_condition)
                CalculateMatrix(ref matrix);
}

And then the bug “came” 🙂
Nothing worked… After many iterations, suddenly became clear, that all the matrices have same content. Short debug recovered the problem: since “Matrix3X3” is defined as a class, all matrix references have a “pointer” to the same instance! The instance, that was constructed for static Ones matrix! Indeed, all matrices’ reference the static member. Hence, every change of any matrix (e.g. by the function “CalculateMatrix”), change simultaneously all matrices, which was initialized by those static feilds assign. Oops…

How can one fix the problem? Very simple: define “Matrix3X3” as a structure rather then a class. Definitely, structure is a value-type (whereas class is a reference-type), and it is copied by-value. Hence, the line “matrix = Matrix3X3.Zero;” makes a deap copy of matrix’s value (on the stack), rather then shallow copy in a case of class.

Note, that there are cases, while this method does not fit: e.g. if the class is too big, or needs to be inherited, it should not be converted to a structure. In those case, we must think about another way.

Can you suggest any interest method? Do you have some ideas?
Please, share them with us …

Categories: .Net Tags: , , ,
  1. Dmitry Rizhikov
    April 16th, 2011 at 17:31 | #1

    Static member exists on class level. It means it is the same for all the instances of the same class.
    I don’t know if this is different in C#, but in Java initialization like this:
    public static Matrix3X3 Zero = new Matrix3X3(0);
    public static Matrix3X3 Ones = new Matrix3X3(1);
    means it’s performed in constructor.
    So basically when you do
    matrix = Matrix3X3.Ones;
    without explicitly calling the constructor: new Matrix3X3(1);
    your matrix is null.

  2. GenEric
    April 17th, 2011 at 00:47 | #2

    Static members definitely exist on class level – shared for all objects of this class. That was exactly the reason for memory corruption.
    I am not sure how it is in Java, but in C#.NET there is a static constructor, which initializes static members. A line like “public static Matrix3X3 Zero = new Matrix3X3(0);” behaves almost as static constructor (up to “beforefieldinit” flag, but this is another story).
    Hence, the constructor has been called to initialize “Ones” feild. And this is not the constructor of “this”! Now all object of “Matric3X3” reference same member, allocated in heap and corrupt them while unappropriate use.

  3. Cameron
    August 5th, 2012 at 07:16 | #3

    The only reason changing to use a struct makes this work is because structs are copied value wise on assignment, they cannot be assigned by reference (not without doing some extra work). Thus your matrix1 = Matrix3X3.Ones; returns a member-size copy of the static member if Matrix3X3 is a struct.

    You could then say matrix2 = matrix1; and again, the information would be copied, changing matrix1 after this assignment would not alter matrix2.

    The alternative, if you actually want to keep references to matrices in your code (using a Class), is to make Matrix3X3.Ones a property that explicitly constructs a new object and returns it.

    public static Matrix3X3 Ones {
    get {return new Matrix3X3(1);}
    }

  1. No trackbacks yet.