.NET - Pass By Reference
.NET - Pass By Reference

How to pass a reference type TRULY as reference ?

Is this title confusing ? I must admit thought a lot about what should be the title of this blogpost and could not come up with better than this one. Do you think that reference types are always passed by reference ? This article discusses this question and tries to highlight some interesting facts.

So, what is it about ?

This is one of my favorite topic since I have learnt C#. Let’s talk about why this question came to my mind.

We all know that there are two main categories of types – value types and reference types.

  • A value type variable contains instance of the value. On the other hand, a reference type variable contains a reference to an instance of that type.
  • Also, when a value type variable is assigned to another variable of same value type, the value is copied to the new variable. It means, two memory locations containing same values, hence changing value in first variable does not affect the other variable’s value. On the other hand, when a reference type variable is assigned to another variable of same type, the reference to the instance is copied. It means if some properties from the instance of reference type are modified using first variable and second variable is used to read the values from the instance, the modifications can still be seen, because underlying instance was same.

C# has many value types, some of them are int, short, long, char, bool, etc. C# also has multiple ways to define the reference types. Some common types are the classes, arrays, string, object, etc.

The two differences listed above are really important for today’s discussion. The discussion is about passing arguments to a method. In rest of the article, we are going to talk about how reference types are passed as arguments to the methods.

Value Types as Arguments

I think discussion in this section is quite obvious. But still putting it here for the sake of completeness of discussion.

TLDR; Value types are passed by value to the called method, means modifications done in called method are not retained. Value types can also be passed by reference by using ref or out keywords.

When a value type is passed as argument to a method, its value is copied over. It means another copy of the instance is created. This means if passed value is modified inside the called method, those changes would not reflect in the variable used in caller.

But in some cases, we may want the modifications back in the caller method. For such cases, we can use either ref or out keywords with parameters.

The ref keyword is to pass reference to the instance of passed parameter. It can be used to pass a value and get the modified value in the same variable which was used to pass the argument to the method.

The out keyword also passes reference to the instance of passed parameter. It is one way to get more than one return values from the called method.

Main difference between ref and out keyword is – in the called method, the parameter with out keyword is mandatorily required to be set to a value before returning from the method. If out parameter is not assigned with any value in the called method, it would cause a compile time error.

Below is a code example and its output explaining how value types can be passed as arguments – with and without ref keyword. It also shows output of the methods to prove that modified value comes back to the argument only if ref is used.

The code should show an output as shown in below snapshot:

Value Types – Pass by value and Pass by reference

Reference Types as Arguments

Now, this is where the fun begins !

We have already stated that a variable of reference type always holds a reference to an instance of that reference type.

That also means – if a reference type is passed as arguments, a reference to the instance is passed. So the called method gets a reference which points to original instance of the type. That also means, if I make any modifications to the original object, they would be still available in the caller method.

Below is a code example that shows how the caller method still gets the modified values even though the called function modified them. Note that we have not used ref keyword here.

The snapshot below shows output from the code. So the modifications done by called method are available in the caller.

Reference type as arguments

Does this mean that reference types are by default passed by reference ? If yes then, would we ever need to use ref keyword with a parameter of reference type ?

A bit of play around

We already have seen that if some properties of an existing object are changed inside called method, the modifications are still available in the caller. It means that reference types are always passed by reference. But to confirm this, let’s go for an experiment.

This time the called method would create new instance instead of using the passed instance. If the argument is truly being passed as reference, the new object should be available for the caller. Below is the new modified code from ReferenceTypeDemo class. Rest of the code is same as shown in previous code snippet.

Below is the output of the code. It shows that the new object created inside called method is not available to the caller. What does this mean ? Does this mean that reference types are not passed by reference?

An Experiment with Reference Type Parameter

So, What did exactly happen here ?

Let’s try to understand why new object created inside called method was not available to the caller.

Below snapshot shows conceptual representation of what happened. When ChangeObject method was called, both caller method and called methods were pointing to same object.

Next, when called method created new object, the variable from called method was pointing to a new memory location.

When the execution flow returned from called method, all the variables (including parameters) were released by the process, without really changing the value of original variable in caller method.

It means the reference to actual object (E6 in the snapshot below) was copied to a new location, as if it was an integer value. Because of this, the original variable from caller method stayed unaffected when a new object was created inside called method.

Reference Type – Passed by Value

Reference Type – Pass by reference

By now, you have got the idea that without using ref keyword, reference types are “passed by value” – because their references are copied from one place to other.

What if a code needs to pass a reference type variable by reference ? The solution is simple – use ref keyword. Below is a code example which shows a sample code and its output.

The output of above code is shown below. As you can see, the object created inside the called method is available to the caller too.

Reference Type – Pass by reference output

Summary

Like value types, reference types can also be passed to the called methods by two ways – by value and by reference.

When a reference type is passed by reference by using ref keyword, it is truly passed as reference. The called method can either change existing properties or it can create a new object. In both cases, caller method can access the modifications.

Thus, ref keyword is the only way to truly pass any type as reference. It is not very common to use ref keyword with reference types, at least I have not seen it or used it very frequently. But, you should always be aware of the basics, so that you can use the language more effectively.

I hope you find this information helpful. Have you also done some similar experiments ? Let me know by commenting here on the post. You can also connect with me on twitter for conversations.

Leave a ReplyCancel reply