The ref keyword in C# with Reference and Value types

I am a developer from Toronto, Canada and I enjoy writing about JavaScript, Angular and the .NET framework.
Search for a command to run...

I am a developer from Toronto, Canada and I enjoy writing about JavaScript, Angular and the .NET framework.
No comments yet. Be the first to comment.
In this series, I will post articles going over the C# language and other .NET related topics
In .NET, as with many other languages, we use Value types and Reference types. Value types are stored on the stack (if they are not contained inside a reference type), and Reference types are stored on the heap. Boxing is taking a Value type and stor...
What does 99.99% mean?

Using Projections - getting related data

Expose an entity using HotChocolate

Reactive programming is somewhat of a shift in thinking on how you get values from a source of data. Instead of you asking the source every few seconds for an update, the source sends you data you are interested in over time. In other words, we are t...

Learn to create your own tags like control

The ref keyword in C# can be used when passing a variable that holds a Value or a Reference type to a function.
In this article I want to show you how this keyword works and how you can take advantage of it to avoid a possible bug.
When you have a struct or an Integer that's passed by ref to a function, changing the variable value in the function will change the original variable value that was passed to the function.
// assuming we have struct Book
void TestRef(ref Book b) {
b.Name = "New Name";
}
var book = new Book() {
Name = "Old Name"
};
Console.WriteLine(book.Name); // Output: Old Name
TestRef(ref book);
Console.WriteLine(book.Name); // Output: New Name
The results we get here makes sense. We are passing a Value type and because we used the ref keyword, we are going to be changing the original book's Name property.
Here is what is happening:
Now let's look at what happens when you pass in a reference type with the ref keyword!
To explain reference types, let's first look at how reference types work without the 'ref' keyword:
// assuming we have class Book - a reference type
void TestRef(Book b) {
b.Name = "New Name";
}
var book = new Book() {
Name = "Old Name"
};
Console.WriteLine(book.Name); // Output: Old Name
TestRef(book);
Console.WriteLine(book.Name); // Output: New Name
Did you notice that we get the same behaviour as a Value type with the 'ref' keyword?
Passing by Reference without the ref keyword, or a Value type with a ref keyword
As you can see, the local variable 'b' in the function points to the variable on the stack. This in turn points to the heap where the actual Book object lives. When we make a change to the Name property on b, we are actually changing the value on the Heap.
What happens if you create a new Book inside TestRef and assign it to the variable b?
// assuming we have class Book - a reference type
void TestRef(Book b) {
b.Name = "New Name";
b = new Book() {
Name = "Changed"
};
}
var book = new Book() {
Name = "Old Name"
};
Console.WriteLine(book.Name); // Output: Old Name
TestRef(book);
Console.WriteLine(book.Name); // Output: Changed <- this changed
Our function has the power to mess up with the book variable's value! This could be a source of a bug if we are not careful.
Passing by reference without ref keyword - gotcha!
So, now we have a question to ask - how do we stop reference types from being reassigned in the TestRef function? If you guessed it, it is by using the ref keyword.
Here is the same code, but this time we are using the ref keyword with our reference type.
// assuming we have class Book - a reference type
void TestRef(ref Book b) {
b.Name = "New Name";
// Code below does not change original book address
b = new Book() {
Name = "Changed"
};
}
var book = new Book() {
Name = "Old Name"
};
Console.WriteLine(book.Name); // Output: Old Name
TestRef(ref book);
Console.WriteLine(book.Name); // Output: New Name
When we use ref on a reference type, the 'b' variable on TestRef points to the actual item on the heap. In other words, we now have 2 references to the heap.
Here is 'Before creating a new instance of Book in the 'TestRef' function:

And here is 'After creating a new instance of Book in the TestRef' function:

In short, using ref with reference types stops us from re-assigning a new object to the caller variable passed to our function.
Note that ref cannot be used with asynchronous methods!