Deep C# - Passing Parameters |
Written by Mike James | |||||
Thursday, 19 November 2015 | |||||
Page 2 of 4
Pass by referenceIf you want to you can pass parameters by reference and in this case things can seem even more complicated but it is very important to understand what is happening if you are going to avoid even more subtle bugs.
If you want to pass a value type as if it was a reference type you can. All you have to do is to use the keyword ref in front of the appropriate parameter. For example, if you write the original pass by value method as:
Notice that PointV is a stuct and a value type. Now if we create an instance of the PointV struct in the value variable b and set its x field to 5 there is absolutely no difference:
You can see that we have a value variable with the appropriate field values as before:
However when we call MyMethod with a pass by reference parameter
things are very different. Now the local variable a is a reference to the variable b and what you do to a.x is done to b.x with the result that the change is made to the data in the calling method as shown below
As always when MyMethod terminates all of the local variables including a are destroyed but in this case the change to b persists as shown below.
The overall result is that b.x is changed to 10. This looks like the same behaviour that we got when passing a reference type by value but notice it is a different mechanism. In this case the value assigned to b has been changed whereas in the case of pass by value the value assigned to b did not change.
Passing a reference type by referenceTo see how pass by reference really differs from pass by value you have to consider passing a reference type by reference. If we just repeat the same MyMethod with a reference type passed by reference the result is exactly the same - that is the object on the heap has its b.x field changed. However how this happens is very different because in this case a is a reference to the b variable as in the previous case. When we make a change to a.x this change is passed on to b.x and the object on the heap is changed. That is a references b and so a.x is the same thing as b.x. To see that this is really what happens we need to modify the example slightly.
This simply assigns a new PointR object created on the heap to the parameter. That is PointR is a reference type. If this was pass by value the result would be that b isn’t changed by a change to a and so when MyMethod ended a would still point to the same object. However pass by reference makes a reference to the b variable so changes on a are passed on to b. Going through the same steps we first create a new object for b to reference on the heap and change its x field to 5:
The result is as shown below
Now when we call MyMethod with b as a reference parameter:
what happens is that a new PointV object is created on the Heap and all its fields are set to default values. Next a is assigned a reference to this new object but as a is just a reference to b it is be that is changed to be a reference to the new object as shown below.
Of course as always when MyMethod terminates the local variables including a are destroyed but now in addition we have an orphaned object on the heap which will also be destroyed, eventually, by the garbage collector. With the final result that the new object created by MyMethod is left for the rest of the program to work with as shown below.
As long are you keep in mind the two principles that passing by value never changes the passed variable whereas pass by reference can make changes you should be able to work out what is going on. For example, what do you think happens in the previous example if you pass the reference type by value i.e. remove the ref keyword? You should be able to see that in this case it is the new object which is orphaned when MyMethod returns because now there are no remaining references to it.
An old fashioned way of explaining this behaviour is to say that a when you pass by reference you are passing a pointer to the variable in the calling program. References after all are simply safe pointers. When the variable passed is a value type we have a pointer to the value. When the variable passed is a reference type then it is already a pointer to an object in its own right and we have a pointer to a pointer to object.
In short: All variables are by default passed by value. For value and reference types any changes made to the parameter are lost when the method returns. However for reference types any changed made to the object that a parameter references are permanent. If you opt to pass variables by reference using the “ref” keyword then in all cases what is passed into the method is a reference to the parameter. If you change the parameter, or any object that it might reference, within the method then the change is permanent in the object and the parameter. |
|||||
Last Updated ( Thursday, 19 November 2015 ) |