Common Type System—Pass-by-Value and Pass-by-Reference


Jump to: navigation, search
Visual C# Tutorials
.NET Framework Tutorials

Common Type System

© 2006 Wiley Publishing Inc.

Pass-by-Value and Pass-by-Reference

Pass-by-value is also known as pass by copy. What happens here is that a copy of the argument is made and then passed to the receiving method. If the callee method modifies the value of the argument inside of its method body, the caller will never see the results of these modifications. In the case of object references, the value is actually the memory location. This leads many people to believe that passing an object reference is pass-by-reference, which is very incorrect. We’re making a copy of the reference, and passing that copy. The copy ends up pointing to the same address, true, but the method receiving the argument cannot change our original reference to point at a different object.

Pass-by-reference, as you might imagine, supplies the callee with a reference to the same location that the caller’s argument was pointing to, enabling the method’s body to access the shared reference and even change it to point elsewhere. If the caller were to pass a reference to one of its data, it would notice updates made by the method body. Note that verifiability guarantees that a reference to data cannot outlive the data itself. Pass-by-reference is not used as the default in C# and must be explicitly declared by the method and the caller in C# if you intend to use it. Note that VB uses the ByVal and ByRef keywords to indicate the behaviors.

For example, this type declares a method with a byref argument:

public void Swap<T>(ref T x, ref T y)
{
   T t = x;
   x = y;
   y = t;
}

Accessing a value passed by reference—even if it’s a value type—requires an extra dereference to get to the data the byref points at. In the above example, the values for x and y are the addresses of the caller’s arguments, not the values themselves. The result of executing the Swap method is to swap the values referenced by two argument references to occupy the location of the other. This isn’t possible with pass by value because in the body where we modify x and y, we’d be changing the value of the method’s local copies, not shared data. The modifications wouldn’t be visible to the caller and would be entirely lost.

To call this method in C#, the user has to explicitly state that they wish to supply a byref argument:

void Baz()
{
   string x = "Foo";
   string y = "Bar";
 
   // Print the original values of x and y:
   Console.WriteLine("x:{0}, y:{1}", x, y);
 
   // Perform the swap...
   Swap<string>(ref x, ref y);
 
   // Now, print the modified values of x and y:
   Console.WriteLine("x:{0}, y:{1}", x, y);
   }

Executing this code will demonstrate that, prior to the call to Swap, x refers to the "Foo" string and y refers to the "Bar" string. After calling Swap, x refers to "Bar" and y refers to the location of "Foo". Strings were used to illustrate the effect, since clearly strings are immutable; their contents could not have been modified by the Swap function, rather the values of the x and y pointers in Baz’s local address slots must have been.

This has the effect of using load address instructions in the IL, rather than the typical load value. Suffice it to say for now that passing, for example, x in the above example by reference involves loading the address of the x local variable, using the ldloca instruction.


Previous_Page_.gif Next_Page_.gif





Personal tools