Value types can also be created by using the new keyword. Using the new keyword initializes the variable with the default value obtained from the type's default constructor:

int a = new int(); // using the default constructor via the new keyword
return a; // returns "0" in the case of type Int.

Value types can be declared without being initialized, but they must be initialized to some value before being used:

int a; // This is perfectly acceptable
return a; // NOT acceptable! You can't use "a" because "a" doesn't have a value!

Value types cannot equal null. .NET 2.0 provides a Nullable type to get around this limitation, which is discussed in the next section, but null is not a valid value for value types:

int a = null; // Won't compile - throws an error.

If you copy a Value type to another Value type, the value is copied. Changing the value of the copy has no effect on the value of the original. The second is merely a copy of the first - they are in no way connected after assignment. This is fairly intuitive:

Changing the value of the copy (var2 in this instance) had no effect on the value of the original (var1). This is different from reference types which copy a reference to the value, not the value itself.

Value types cannot be derived from.

Value types as method parameters are passed by value by default. A copy of the value-type is made and the copy is passed to the method as a parameter. If the parameter is changed inside the method it will not affect the value of the original value type.

To do:
Eventually we could add an example showing the usage of some of the built-in value type: integer, floating point, logical, char and decimal and the value parameter passing of value types

While not for use solely with Nullable types, the ?? operator proves very useful when you want to use a default value instead of a null value. The ?? operator returns the left operand of a statement if not null, otherwise it returns the right operand.

Building a value type must be very simple. The following example defines a custom "point" structure with only 2 double members. See boxing and unboxing for a discussion of implicit conversion of value types to reference types.

The following sample shows simple uses of the System enumeration DayOfWeek. The code is much simpler to read than testing for an integer value representing a day. Note that using ToString() on an enum variable will give the string representation of the value (ex. “Monday” instead of “1”).

The possible values can be listed using Reflection. See that section for details.

Reference types are more commonly referred to as objects. Classes, Interfaces and Delegates are all reference types, as well as the built-in reference types System.Object and System.String. Reference types are stored in managed Heap memory.

Unlike Value types, reference types can be assigned the value null.

Copying a reference type copies a reference that points to the object, not a copy of the object itself. This can seem counter-intuitive at times, since changing a copy of a reference will also change the original.

A Value type stores the value it is assigned, plain and simple - but a Reference type stores a pointer to a location in memory (on the heap). Think of the heap as a bunch of lockers and the Reference type holds the locker number (there are no locks in this metaphor). Copying a Reference type is like giving someone a copy of your locker number, rather than a copy of its contents. Two Reference types that point to the same memory is like two people sharing the same locker - both can modify its content:

Since the yourDog variable and the the myDog variable both point to the same memory store, the ouput of which would be:

Your dog is a Mutt that is 13 years old.
My dog is a Mutt that is 13 years old.

As a practice for manipulating reference types you may want to work with the String and StringBuilder classes. We have put these with the text manipulation section but manipulating strings is a basic operation of almost all programs.

The use of the four major categories of System Generic Types will mainly be demonstrated elsewhere in this book:

The nullable type was discussed above

A whole section follows on Generic collections

The generic event handler will be discussed in the Event / Delegate section.

The generic delegates will also be discussed in the Event / Delegate section as well as in the Generic collections section (Comparer class).

If you copy the next very simple example in Visual Studio and try to add something other than an int to the list the program will not compile. This demonstrates the strong typing capability of generics.

Next step is to present an example including a generic interface, a generic class that implements that generic interface and a class derived from that generic class. The sample also uses interface and derivation constraints.

This is another simple problem involving employees and suppliers which have nothing in common except that they can request payment to a "payment handler" (see visitor pattern).

The problem is to know where to put the logic if you have specific processing to do for a certain kind of payment just for employees. There are myriads of ways to solve that problem but the use of generics make the following sample clean, explicit and strongly typed.

The other nice thing is that it has nothing to do with containers or collections where you will find almost all of generic samples.

Please note that the EmployeeCheckPayment<T> class derives from CheckPayment<T> giving a stronger constraint on the type parameter T (must be employee not just implement IPaymentInfo). That gives us the to opportunity to have access (in its RequestPayment method) to all payment logic (from the base class) at the same time as all employee public interface (thru the sender method parameter) and that without having to do any cast.

All types derive directly or indirectly from System.Object (including value types by the way of System.ValueType). This allows the very convenient concept of a reference to "any" object but poses some technical concerns because value types are not "referenced". Comes boxing and unboxing.

Boxing and unboxing enable value types to be treated as objects. Boxing a value type packages it inside an instance of the Object reference type. This allows the value type to be stored on the garbage collected heap. Unboxing extracts the value type from the object. In this example, the integer variable i is boxed and assigned to object o:

int i = 123;
object o = (object) i; // boxing

Please also note that it is not necessary to explicitly cast an integer to an object (as shown in the example above) to cause the integer to be boxed. Invoking any of its methods would also cause it to be boxed on the heap (because only the boxed form of the object has a pointer to a virtual method table):

int i=123;
String s=i.toString(); //This call will cause boxing

There is also a third way in which a value type can be boxed. That happens when you pass a value type as a parameter to a function that expects an object. Let's say there is a function prototyped as:

void aFunction(object value)

Now let's say from some other part of your program you call this function like this:

int i=123;
aFunction(i); //i is automatically boxed

This call would automatically cast the integer to an object, thus resulting in boxing.

The object o can then be unboxed and assigned to integer variable i:

o = 123;
i = (int) o; // unboxing

Performance of boxing and unboxing

In relation to simple assignments, boxing and unboxing are computationally expensive processes. When a value type is boxed, an entirely new object must be allocated and constructed. To a lesser degree, the cast required for unboxing is also expensive computationally.