In this article, we are still going to talk about methods but from a different perspective. We are going to learn how to pass our arguments by using the ref and out keywords.
For the complete navigation of this series check out: C# Back to Basics.
Let’s dive in.
What are ref and out Keywords in C#?
In the previous post, we were passing value-type arguments while calling our methods.
Why is the type of the argument important here?
Well, when we pass the argument of type int, double, decimal, etc (basic value types), we do not pass the actual value but its copy. This means that our original values are not changed inside the methods, because we pass a new copy of the original value.
As a result, all the operations inside a method are executed upon the copy value:
class Program { public static void ChangeAndWrite(int number) { number = 10; Console.WriteLine($"Inside ChangeAndWrite method, number value is: {number}"); } static void Main(string[] args) { int number = 5; Console.WriteLine($"Value of the number prior to ChangeAndWrite call is: {number}"); ChangeAndWrite(number); Console.WriteLine($"Value of the number after the ChangeAndWrite call is: {number}"); Console.ReadKey(); } }
The output:
Value of the number prior to ChangeAndWrite call is: 5 Inside ChangeAndWrite method, number value is: 10 Value of the number after the ChangeAndWrite call is: 5
As we can see, the value of the number variable changes only inside the ChangeAndWrite
method. But the original value is the same as before calling the ChangeAndWrite
method. And again, this is because we are passing the exact copy of the original value.
Using Ref and Out Keywords
We can change this default behavior. If we want to change the original values inside our methods, we can do that by using ref
and out
keywords inside the method signature and inside the method call as well.
We can use the ref
keyword only if the variable which we use as an argument is initialized before calling a method. By using the out
keyword, we don’t have to initialize a variable before calling a method but, we must initialize it inside a method.
So, let’s simplify that.
If we want to change an existing value of a variable inside a method, we are going to use the ref
keyword. But, if we want to assign a completely new value to the variable inside a method, then we use the out
keyword.
Ref and Out With Value Types
In this example, we are going to see the behavior of value type variables when we use ref
and out keywords:
class Program { public static void ChangeRef(ref int numberRef) { numberRef = 25; Console.WriteLine($"Inside the ChangeRef method the numberRef is {numberRef}"); } public static void ChangeOut( out int numberOut) { numberOut = 60; Console.WriteLine($"Inside the ChangeOut method the numberOut is {numberOut}"); } static void Main(string[] args) { int numberRef = 15; Console.WriteLine($"Before calling the ChangeRef method the numberRef is {numberRef}"); ChangeRef(ref numberRef); Console.WriteLine($"After calling the ChangeRef method the numberRef is {numberRef}"); Console.WriteLine(); int numberOut; Console.WriteLine("Before calling the ChangeOut method the numberOut is unassigned"); ChangeOut(out numberOut); Console.WriteLine($"After calling the ChangeOut method the numberOut is {numberOut}"); Console.ReadKey(); } }
Let’s see what our output looks like after these changes:
Before calling the ChangeRef method the numberRef is 15 Inside the ChangeRef method the numberRef is 25 After calling the ChangeRef method the numberRef is 25 Before calling the ChangeOut method the numberOut is unassigned Inside the ChangeOut method the numberOut is 60 After calling the ChangeOut method the numberOut is 60
If we use the ref
or the out
keyword on the value type variable, its original value will change.
But the difference is that with the out
keyword we can use unassigned variables.
Ref and Out With Reference Types
We’ve learned, that the reference type doesn’t store its value inside its own memory location. It stores the address towards the memory location where the value is stored. Therefore when we send an argument as a reference type to the method and change that parameter, the original value is changed.
This is because we are not sending the copy of the value but the copy of the address that points to the original value. This is the same thing as when we use the ref
keyword with the value types.
Still, we can use the ref
keyword with the reference types if we want to create a new object with the same address:
class Program { public static void ChangeColor(Pen pen) { pen.Color = Color.Green; Console.WriteLine($"Inside the ChangeColor method the color is {pen.Color}"); } public static void CreateNewObjectWithoutRef(Pen pen) { pen = new Pen(Color.Red); Console.WriteLine($"Inside the CreateNewObjectWithoutRef method the color of new pen object is {pen.Color}"); } public static void CreateNewObjectWithRef(ref Pen pen) { pen = new Pen(Color.Yellow); Console.WriteLine($"Inside the CreateNewObjectWithRef method the color of new pen object is {pen.Color}"); } static void Main(string[] args) { Pen pen = new Pen(Color.Blue); Console.WriteLine($"Before ChangeColor method: {pen.Color}"); ChangeColor(pen); Console.WriteLine($"After the ChangeColor method: {pen.Color}"); Console.WriteLine(); Console.WriteLine($"Before CreateNewObjectWithoutRef method: {pen.Color}"); CreateNewObjectWithoutRef(pen); Console.WriteLine($"After CreateNewObjectWithoutRef method: {pen.Color}"); Console.WriteLine(); Console.WriteLine($"Before CreateNewObjectWithRef method: {pen.Color}"); CreateNewObjectWithRef(ref pen); Console.WriteLine($"After CreateNewObjectWithRef method: {pen.Color}"); Console.ReadKey(); } }
Before ChangeColor method: Blue Inside the ChangeColor method the color is Green After the ChangeColor method: Green Before CreateNewObjectWithoutRef method: Green Inside the CreateNewObjectWithoutRef method the color of new pen object is Red After CreateNewObjectWithoutRef method: Green Before CreateNewObjectWithRef method: Green Inside the CreateNewObjectWithRef method the color of new pen object is Yellow After CreateNewObjectWithRef method: Yellow
In the first method, we are not using the ref
keyword. The value is different because we pass the copy of the address in which the original value is stored.
In the second method, the original value stays the same. That’s because we create a new object inside the method thus the new memory address is allocated.
In the third method, we are using the ref keyword, and the original value changes. Why? Because with the ref
keyword we are copying the same address to a new object.
ref vs out
Here are the main differences between these two keywords summed up:
ref keyword | out keyword |
---|---|
Parameters should be initialized before being passed to "ref". | Parameters don't need to be initialized before being passed to "out". |
Not necessary to initialize the value of a parameter before returning it to the calling method. | It is necessary to initialize the value of a parameter before returning it to the calling method. |
The passing of value through "ref" parameter is useful when the called method needs to change the value of that parameter. | Useful when a method returns multiple values. |
When "ref" is used the data passage is bidirectional. | When "out" keyword is used the data flows in one direction. |
Conclusion
Now we know how to use the ref and out keywords with the value and reference types. This is quite a useful feature in C#, thus knowing how to work with those keywords is an advantage for the developers.
In the next post, we will talk about recursion and recursive methods.