The simple data types, int, char, etc are clearly value types, but conceptually at least they are also examples of structs. Most of the time you can ignore this fact and just treat them as simple numbers or characters, but they do have methods. For example, int is just an alias for the System.Int32struct which inherits from object and so it has a ToString method:
string b = a.ToString();
Each simple type also has methods of its own and even static methods. For example:
int I =
Of course, you can’t inherit from a simple type and they have other special features such there being literals of the same type, e.g. 10, 233.34 and so on.
Simple types are structs in spirit only as the compiler takes care to make sure that they are implemented in an efficient manner. Notice that, as with a struct, you can opt to create a simple type using the new keyword. This doesn’t have any effect other than to call the type’s default constructor which results in it being initialized to its default value. So, for example:
I = j;
results in a compiler error because j isn’t defined. However:
int j = new int();
I = j;
works perfectly because j is initialized to 0 by its constructor.
Value or Reference - Decide Early, Don't Change
You should by now understand the difference between a value and a reference type, but when do you use one in preference to another? In most cases this question is simply about using a class or a struct. The answer is nearly always that you should prefer a value type when the purpose is to store data and a reference type when some behavior has to be implemented. Whichever you choose, you need to be aware of the potential for trouble that any attempt at changing a value type to a reference type can produce. For example, suppose we initially design a program using a struct:
public int x;
We might very well use a method to do some computation involving a private instance of this struct:
MyStruct MyData = new MyStruct();
In this example no computation is performed - the struct is simply returned. Now if some other part of your program uses this method it might well go on and perform further manipulations on the returned value:
a = doSum();
a.x = 10;
In this case everything works as you would expect. The struct is treated using value semantics and the doSum returns a complete copy of the struct to create a completely separate entity in a. This means that storing 10 in the x field doesn’t alter the value stored in MyData.
Now consider the seemingly small change from a struct to a class:
public int x;
The change to the private variable and the method are easy enough:
MyClass MyData = new MyClass();
However, if the client program performs the same manipulation:
a.x = 10;
the result is very different. Now the object passed as the result is treated as a reference type and subject to reference semantics. This means that doSum passes back a reference to the, supposedly protected, Mydata object. Now when we store 10 in the x field, it is the field in the Mydata object which is changed.
Clearly changing from a value type to a reference type and vice versa is a potentially deep structural change to a program because it changes value semantics into reference semantics.
In Chapter But Not In This Extract
Alternative to Structs I – Tuple
Alternative to Structs II – Record
Structs are value types, but classes are reference types and never the twain shall meet. Well at least you should keep them well apart in your mind because they behave differently and they are for very different purposes. C#’s structs are more sophisticated than the same idea implemented in other languages and, partly to make up for this, we have two alternatives – the tuple and the record. Both are useful, but it is possible to become excessively addicted to the tuple as a way of temporarily packaging data into a single entity that can be passed around.