.

Tuesday, June 17, 2008

Primer On Reference types and Value types

Reference types

Reference types store a reference to the value’s memory address and are allocated on the heap. Reference types can be self-describing types, pointer types, or interface types. The data type can be determined from values of self-describing types. Self-describing types are further split into arrays and class types. The class types are user-defined classes, boxed value types, and delegates.

The .NET Framework includes a variety of reference types; this includes the String object, along with all arrays (even if their elements are value types), class types, and delegates. You can think of a reference type as anything that inherits from the Object class; this means that every object you create is a reference type.

One way to identify a reference type is by using a new keyword that isn’t used for value types. The following C# snippet shows the creation of a StringBuilder object, which is a reference type.

StringBuilder sb = new StringBuilder();

When the runtime deals with reference types, it allocates two spaces in memory: one for the actual object (StringBuilder in the previous example) and one for its reference (sb in the previous example). The actual object is stored on the managed heap, so it is within the reach of the garbage collector. The dispose method is used to release its memory and make it available to the garbage collector.

On the other hand, the reference to the object is stored on the stack. When using reference types, the ref keyword is used in both the method signature and when it is called in C# to tell the system that you are working with a reference to the object. In VB.NET, ByRef is used in the method signature with nothing when the method is called.

Value types

Simply put, a value type contains its data. Furthermore, they are either allocated on the stack or allocated inline in a structure. Value types can be built-in (implemented by the runtime), user-defined, or enumerations.

The .NET Framework includes numerous built-in value types; this includes all numeric data types, the Boolean, Char, and Date classes along with all structures (even if their members are reference types), and enumerations. Value types inherit directly from the System.ValueType class; however, value types are sealed so you may not derive other classes from them.

Value types are directly accessed — there is no need for the new keyword. The following VB.NET snippet shows the creation of a couple of value types.

Dim counter As Integer
Dim finished As Boolean;
counter = 1;
finished = false;

Value types are stored on the stack, so they are not affected by the garbage collector. When the .NET runtime works with value types, it deals directly with its underlying data. Value types are often referred to as lighter types as opposed to heavier reference types.

Reference and value types in action

The following simple example demonstrates the use of reference types (via a new keyword). A simple Person class is used (first and last name along with a title). Two methods (overloaded SwapPeople) are used to manipulate instances of the class.

This example also illustrates a feature of the .NET Framework and its ability to seamlessly move between reference and value types. The compiler often moves between the two types automatically in the background; this is called boxing and unboxing. The concept is demonstrated in the SwapValue method.

Each method swaps the objects by setting them to each other using a temporary object. The first method accepts two Person objects that are passed by reference (the ref keyword). Notice that the ref keyword is used in both the method signature and when it is actually called. The second method does not use the ref keyword, so the actual objects are passed.

The first method swaps the objects, and the swap is recognized outside the scope of the method since references are used. The second method swaps the objects, but it is only visible within the method since the actual object is used (no ref passed). Each method uses an instance of the Person class called Temp, which is set to one of the objects passed to the method. It doesn’t get the values of the object, but rather it points to the memory space containing the object.

The third method swaps two value types (integers) via references. It utilizes boxing to convert them to reference types, so the changes are recognized outside of the method. The last method does not use references, so the values are passed to the method with the changes not recognized outside of the method.

using System;
using System.Collections.Generic;
using System.Text;
namespace ValueAndReferenceTypes {
class Program {
static void Main(string[] args) {
int a = 1;
int b = 2;
Console.WriteLine("a=" + a.ToString() + " b= " + b.ToString());
SwapValue(ref a, ref b);
Console.WriteLine("a=" + a.ToString() + " b= " + b.ToString());
SwapValue(a, b);
Console.WriteLine("a=" + a.ToString() + " b= " + b.ToString());
}



public static void SwapValue(ref int a, ref int b) {
int t;
t = a;
a = b;
b = t;
}
public static void SwapValue(int a, int b) {
int t;
t = a;
a = b;
b = t;
} }

The following output is generated:


a=1 b= 2
a=2 b= 1
a=2 b= 1

No comments:

.