Page 2 of 3
Structs and classes
Although value types are often introduced as “simple” types such as int or float all value types are really just examples of the struct.
The simple value types are stucts but they are also treated differently to avoid the overheads a genuine struct brings with it to make sure that your program runs efficiently. The fact that an int is a struct really only has an impact on your programs because this means that int inherits from object a set of simple standard methods. For example, it is perfectly ok to write:
In fact int is just an alias for the System.Int32 struct. You could write
in place of int a but it is usual not to. We will return to the issue of simple data types as objects later in this chapter because there is a little more to it.
So it is reasonable to say that the most important division in C# type system is the split into classes and structs (both descended from object). And the really big difference between the two is that a class is a reference type whereas a struct is a value type.
In many cases you have the choice of implementing something as either a class or a struct. For example consider a simple type designed to store the x,y coordinates of a point. You can do this as a class:
public int x,y;
or as a struct:
public int x,y;
Notice that the class is named with a trailing R for Reference and the struct with a trailing V for value.
As already stated the most important difference is due to the fact that a struct is a value type and a class is a reference type. That is the class behaves as described earlier for general reference types and struct behaves like a general value type - but lets take a look at this more closely because a struct and a class look much more alike than say an int and a class and mistakes and misunderstandings are easier to make.
The most immediate impact of this difference is that you don’t have to use “new” when creating an instance of a struct that is you can create an instance of PointV using:
and this immediately creates a PointV object which you can use:
The similar class however needs “new” to create an instance and:
only creates a reference variable. To make use of a PointR object you also have to use:
To make the difference even clearer you can create other references to the same PointR object as in:
Now c and b refer to the same PointR object and the same x value is changed by c.x=30 or b.x=30. In the case of a struct, and a PointV in particular, you cannot create multiple references to it and assignment creates a copy of the struct. That is,
makes an independent copy of the struct a. Now assigning to d.x changes a different x to assigning to a.x.
If you think you follow try predicting the result of (i.e. predict the values in each of the fields) the admittedly complicated:
PointR b=new PointR();
The answer is:
because d is the same object as b but c is a new object initialised to be the same as a.
The difference between the two is usually expressed as value semantics versus reference semantics, i.e. is the variable the value or a reference to the value. The advice is that structs should be used for simple data types where value assignment seems natural and classes should be used for more advanced types where reference assignment is natural.
The “value” semantics also has another spin-off when it comes to arrays and indeed other complex data types. When you create an array you always use something closer to reference-type semantics as in:
int a=new int;
This creates 10 ints in a contiguous block of memory and this is very efficient. Now consider:
PointR b=new PointR;
This creates a contiguous block of 10 reference variables of type PointR all referencing - nothing at all. To finish the array construction you have to use something like:
This is, of course, not as efficient because the 10 objects are created on the heap and have to be memory managed, but all object-oriented languages suffer from this type of problem. The good news is that C# treats arrays created using structs in the same way as simple types, i.e. using value semantics. For example:
PointV c=new PointV;
immediately creates an array of 10 PointV objects in a contiguous block of memory.