Developer

A .NET primer on reference types and value types

Working with reference types and value types is usually not given much thought during daily programming chores; but if you ever choose to pursue .NET certification, you should be familiar with both types. Tony Patton provides you with a solid background in these programming basics.

At the TechEd North America 2008 Developers conference, I heard an interesting talk that focused on .NET programming basics, which spurred a lively discussion on reference types and value types. The more people talked, it was obvious how many people misunderstand the subject. With that in mind, I decided to cover the topic to make sure all .NET developers are on the same page.

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) {

Person person1 = new Person();

person1.Populate("Mary", "Weilage", "Editor");

Person person2 = new Person();

person2.Populate("Tony", "Patton", "Contributor");

Console.WriteLine("Before swap...");
Console.WriteLine(person1.FirstName + " " + person1.LastName + " — " + person1.Title);
Console.WriteLine(person2.FirstName + " " + person2.LastName + " — " + person2.Title);
SwapPeople(ref person1, ref person2);
Console.WriteLine("After swap ...");
Console.WriteLine(person1.FirstName + " " + person1.LastName + " — " + person1.Title);
Console.WriteLine(person2.FirstName + " " + person2.LastName + " — " + person2.Title);
SwapPeople(person1, person2);
Console.WriteLine("After swap ...");
Console.WriteLine(person1.FirstName + " " + person1.LastName + " — " + person1.Title);
Console.WriteLine(person2.FirstName + " " + person2.LastName + " — " + person2.Title);
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 SwapPeople(ref Person per1, ref Person per2) {

Person temp;

temp = per1;

per1 = per2;

per2 = temp;

}

public static void SwapPeople(Person per1, Person per2) {

Person temp;

temp = per1;

per1 = per2;

per2 = temp;

Console.WriteLine("In SwapPeople method ...");

Console.WriteLine(per1.FirstName + " " + per1.LastName + " — " + per1.Title);

Console.WriteLine(per2.FirstName + " " + per2.LastName + " — " + per2.Title);

}

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;

} }

class Person {

public string FirstName;

public string LastName;

public string Title;

public void Populate (string fname, string lname, string title) {

FirstName = fname;

LastName = lname;

Title = title;

} } }

The following output is generated:

Before swap...

Mary Weilage - Editor

Tony Patton - Contributor

After swap ...

Tony Patton - Contributor

Mary Weilage - Editor

In SwapPeople method ...

Mary Weilage - Editor

Tony Patton - Contributor

After swap ...

Tony Patton - Contributor

Mary Weilage - Editor

a=1 b= 2

a=2 b= 1

a=2 b= 1

The VB.NET version of the code follows:

Module Module1

Sub Main()

Dim person1 As New Person()

person1.Populate("Mary", "Weilage", "Editor")

Dim person2 As New Person()

person2.Populate("Tony", "Patton", "Contributor")

Dim temp As Person = person1

Console.WriteLine("Before swap...")

Console.WriteLine(person1.FirstName + " " + person1.LastName + " — " + person1.Title)

Console.WriteLine(person2.FirstName + " " + person2.LastName + " — " + person2.Title)

SwapPeople1(person1, person2)

Console.WriteLine("After call to SwapPeople1(ByRef person1, ByRef person2)...")

Console.WriteLine(person1.FirstName + " " + person1.LastName + " — " + person1.Title)

Console.WriteLine(person2.FirstName + " " + person2.LastName + " — " + person2.Title)

SwapPeople2(person1, person2)

Console.WriteLine("After call to SwapPeople2(person1, person2)...")

Console.WriteLine(person1.FirstName + " " + person1.LastName + " — " + person1.Title)

Console.WriteLine(person2.FirstName + " " + person2.LastName + " — " + person2.Title)

Dim a As Integer = 1

Dim b As Integer = 2

Console.WriteLine("Before call to SwapValue1(ByRef c, ByRef d)...")

Console.WriteLine("a=" + a.ToString() + " b= " + b.ToString())

SwapValue1(a, b)

Console.WriteLine("After call to SwapValue2(c, d)...")

Console.WriteLine("a=" + a.ToString() + " b= " + b.ToString())

SwapValue2(a, b)

Console.WriteLine("After call to SwapValue(c, d)...")

Console.WriteLine("a=" + a.ToString() + " b= " + b.ToString())

End Sub

Public Sub SwapPeople1(ByRef per1 As Person, ByRef per2 As Person)

Dim temp As Person

temp = per1

per1 = per2

per2 = temp

End Sub

Public Sub SwapPeople2(ByVal per1 As Person, ByVal per2 As Person)

Dim temp As Person

temp = per1

per1 = per2

per2 = temp

Console.WriteLine("In SwapPeople method ...")

Console.WriteLine(per1.FirstName + " " + per1.LastName + " — " + per1.Title)

Console.WriteLine(per2.FirstName + " " + per2.LastName + " — " + per2.Title)

End Sub

Public Sub SwapValue1(ByRef c As Integer, ByRef d As Integer)

Dim t As Integer

t = c

c = d

d = t

End Sub
Public Sub SwapValue2(ByVal c As Integer, ByVal d As Integer)

Dim t As Integer

t = c

c = d

d = t

End Sub

End Module

Class Person

Public FirstName As String

Public LastName As String

Public Title As String

Sub Populate(ByVal fname As String, ByVal lname As String, ByVal title1 As String)

FirstName = fname

LastName = lname

Title = title1

End Sub

End Class

Inside the Framework

Working with reference types and value types is usually not given much thought during daily programming chores; but if you ever choose to pursue .NET certification, you should be familiar with both types. Also, a solid understanding of both types helps in everyday programming tasks.

Are there aspects of the .NET Framework that you find confusing or have always wondered about? Let me know in the Web Developer discussion.

Tony Patton began his professional career as an application developer earning Java, VB, Lotus, and XML certifications to bolster his knowledge.

———————————————————————————————————————————-

Get weekly development tips in your inbox Keep your developer skills sharp by signing up for TechRepublic's free Web Developer newsletter, delivered each Tuesday. Automatically subscribe today!

About

Tony Patton has worn many hats over his 15+ years in the IT industry while witnessing many technologies come and go. He currently focuses on .NET and Web Development while trying to grasp the many facets of supporting such technologies in a productio...

Editor's Picks