Exercise - Discover reference types
Reference types include arrays, classes, and strings. Reference types are treated differently from value types regarding the way values are stored when the application is executing.
In this exercise, you learn how reference types are different from value types, and how to use the new
operator to associate a variable with a value in the computer's memory.
How reference types are different from value types
A value type variable stores its values directly in an area of storage called the stack. The stack is memory allocated to the code that is currently running on the CPU (also known as the stack frame, or activation frame). When the stack frame has finished executing, the values in the stack are removed.
A reference type variable stores its values in a separate memory region called the heap. The heap is a memory area that is shared across many applications running on the operating system at the same time. The .NET Runtime communicates with the operating system to determine what memory addresses are available, and requests an address where it can store the value. The .NET Runtime stores the value, and then returns the memory address to the variable. When your code uses the variable, the .NET Runtime seamlessly looks up the address stored in the variable, and retrieves the value that's stored there.
You'll next write some code that illustrates these ideas more clearly.
Define a reference type variable
Delete or use the line comment operator
//
to comment out all of the code from the previous exercises.Update your code in the Visual Studio Code Editor as follows:
int[] data;
The previous code defines a variable that can hold a value of type
int
array.At this point,
data
is merely a variable that could hold a reference, or rather, a memory address of a value in the heap. Because it's not pointing to a memory address, it's called a null reference.Create an instance of
int
array using thenew
keywordUpdate your code in the Visual Studio Code Editor to create and assign a new instance of
int
array, using the following code:int[] data; data = new int[3];
The
new
keyword informs .NET Runtime to create an instance ofint
array, and then coordinate with the operating system to store the array sized for three int values in memory. The .NET Runtime complies, and returns a memory address of the newint
array. Finally, the memory address is stored in the variable data. Theint
array's elements default to the value0
, because that is the default value of anint
.Modify the code example to perform both operations in a single line of code
The two lines of code in the previous step are typically shortened to a single line of code to both declare the variable, and create a new instance of the
int
array. Modify the code from step 3 to the following.int[] data = new int[3];
While there's no output to observe, hopefully this exercise added clarity to how the C# syntax relates to the steps of the process for working with reference types.
What's different about the C# string data type?
The string
data type is also a reference type. You might be wondering why a new
operator wasn't used when declaring a string. This is purely a convenience afforded by the designers of C#. Because the string
data type is used so frequently, you can use this format:
string shortenedString = "Hello World!";
Console.WriteLine(shortenedString);
Behind the scenes, however, a new instance of System.String
is created and initialized to "Hello World!".
Practical concerns using value and reference types
- Value Type (int): In this example,
val_A
andval_B
are integer value types.
int val_A = 2;
int val_B = val_A;
val_B = 5;
Console.WriteLine("--Value Types--");
Console.WriteLine($"val_A: {val_A}");
Console.WriteLine($"val_B: {val_B}");
You should see the following output:
--Value Types--
val_A: 2
val_B: 5
When val_B = val_A
is executed, the value of val_A
is copied and stored in val_B
. So, when val_B
is changed, val_A
remains unaffected.
- Reference Type (array): In this example,
ref_A
andref_B
are array reference types.
int[] ref_A= new int[1];
ref_A[0] = 2;
int[] ref_B = ref_A;
ref_B[0] = 5;
Console.WriteLine("--Reference Types--");
Console.WriteLine($"ref_A[0]: {ref_A[0]}");
Console.WriteLine($"ref_B[0]: {ref_B[0]}");
You should see the following output:
--Reference Types--
ref_A[0]: 5
ref_B[0]: 5
When ref_B = ref_A
is executed, ref_B
points to the same memory location as ref_A
. So, when ref_B[0]
is changed, ref_A[0]
also changes because they both point to the same memory location. This is a key difference between value types and reference types.
Recap
- Value types can hold smaller values and are stored in the stack. Reference types can hold large values, and a new instance of a reference type is created using the
new
operator. Reference type variables hold a reference (the memory address) to the actual value stored in the heap. - Reference types include arrays, strings, and classes.