.NET Development Foundation/Using System Types

System types and collections: Using System types

Using System types
Exam objective: Manage data in a .NET Framework application by using the .NET Framework 2.0 system types.

(Refer System namespace)

Value types usage
Following are some "usage" oriented remarks about value types.

Value types contain the values they are assigned: int a = 1; // the variable "a" contains "1" of value type int 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: int var1 = 1; int var2 = var1; //the value of var1 (a "1" of type int) is copied to var2 var2 = 25;       // The "1" value in var2 is overwritten with "25" Console.WriteLine("The value of var1 is {0}, the value of var2 is {1}", var1, var2); Which would result in the output: The value of var1 is 1, the value of var2 is 25 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.

Nullable type
See MSDN

A nullable type...

System.Nullable MyNullableInt; // the long version int? MyNullableInt;                 // the short version bool? MyBoolNullable; // valid values: true || false || null Be careful with nullable booleans! In if, for, while or logical evaluation statements a nullable boolean will equate a null value with false—it will not throw an error.
 * Is a generic type
 * Is an instance of System.Nullable struct.
 * Can only be declared on value types.
 * Is declared with System.Nullable or the shorthand type? - the two are interchangeable.
 * Accepts the normal range of values of the underlying type, as well as null.

Methods: T GetValueOrDefault & T GetValueOrDefault(T defaultValue) Returns the stored value or the default value if the stored value is set to null.

Properties: HasValue & Value Nullable types have two read only properties: HasValue and Value.

HasValue is a boolean property that returns true if Value != null. It provides a means to check your type for a non-null value before using it where you might throw an error: int? MyInt = null; int MyOtherInt; MyOtherInt = MyInt.Value + 1;   // Error! You can't add null + 1!! if (MyInt.HasValue) MyOtherInt = MyInt.Value + 1; // This is a better way. Value returns the value of your type, null or otherwise. int? MyInt = 27; if (MyInt.HasValue) return MyInt.Value; // returns 27. MyInt = null; return MyInt; // returns null.

Wrapping / Unwrapping

Wrapping is the process of packaging a value m from a non-nullable type N to a nullable type N? via the expression new N?(m)

Unwrapping is the process of evaluating a nullable type N? for instance m as type N or NULL and is performed via the 'Value' property (e.g. m.Value).

Note: Unwrapping a null instance generates the exception System.InvalidOperationException

'''The ?? Operator' (aka the Null Coalescing'' Operator)

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. int? MyInt = null; return MyInt ?? 27; // returns 27, since MyInt is null For more information see the [http://blog.devstone.com/Aaron/archive/2006/01/02/1404.aspx blog entry by R. Aaron Zupancic on the ?? Operator]

Building a value type
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.

Using a user-defined value type
The above example can be used here. Note that the p variable does not have to be initialized with the new operator.

Using enumerations
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.

For a discussion of the Enum class see MSDN

There is a special type of enumeration called a flags enumeration. The exam objectives do not mention it specifically. See MSDN if you are interested.

Building an enumeration
Building a custom enumeration is pretty straightforward as shown by the following example.

Using reference types
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:

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.

Using and building arrays
See MSDN for reference information.

Using generic types
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.

You can use List instead of List and you will get a list of strings for the same price (you are using the same List(T) class).

Building generics
The programming of a custom generic collection was shown in the article mentioned in the topics discussion.

Here we have an example of a Generic Function. We use the trivial problem of swapping two references. Although very simple we still see the basic benefits of Generics:
 * We don't have to recode a swap function for every type
 * The generalization does not cost us the strong typing (try swapping an int and a string, it wont compile)

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 class derives from CheckPayment 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.

Exception classes
Some links to MSDN:
 * Exceptions and exception handling - MSDN
 * Handling and throwing exceptions - MSDN
 * Exception Hierarchy - MSDN
 * Exception Class and Properties - MSDN

Boxing and unboxing
See MSDN

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.

TypeForwardedToAttribute Class
See MSDN


 * For a discussion of TypeForwardToAttribute in the CLR see MSDN


 * Other possible links: Marcus' Blog, NotGartner