Exercise - Discover reference types

Completed

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

  1. Delete or use the line comment operator // to comment out all of the code from the previous exercises.

  2. 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.

  3. Create an instance of int array using the new keyword

    Update 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 of int 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 new int array. Finally, the memory address is stored in the variable data. The int array's elements default to the value 0, because that is the default value of an int.

  4. 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

  1. Value Type (int): In this example, val_A and val_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.

  1. Reference Type (array): In this example, ref_A and ref_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.

Check your knowledge

1.

In C#, when the new keyword is used to create an instance of a class, where is the memory allocated?