Passing Parameter by Value and by Reference

Parameters Introduction

The original article can be found here at my blog.

As we know, C# is an Object Oriented Programming language and since it is object oriented the users of the objects need to interact with the data members of the objects. That can be done using the member functions of the class. Passing parameters to the member functions or the static functions of the class is an important part of programming, that is why it is very important to understand the ways in which we can pass the parameters to the functions in C#.

Before starting the article you may want to be familiar with the value types and reference types in C# that I have discussed in my one of my articles.

There are basically two ways in which we can pass parameters to the functions in C#.

  1. Pass by Value
  2. Pass by reference

I want to explain both of them one by one.

Pass By Value

  • Passing value types by Value: By default all the parameters are passed by value. For a value type a copy of the instance is created when passing the parameter to the function. Please have a look at the following example to understand it better.
    1. static void Main(string[] args)    
    2. {    
    3.      int localVar = 10;    
    4.      Console.WriteLine(localVar);//print 10    
    5.      MethodUsingByVal(localVar);//prints 20    
    6.      Console.WriteLine(localVar);//prints 10    
    7.      Console.Read();    
    8. }    
    9.   
    10. public static void MethodUsingByVal(int intPara)    
    11. {    
    12.     intPara = 20;    
    13.     Console.WriteLine(intPara);    
    14. }  
    As we can see from the preceding code example, localVar is a variable of type int and is assigned a value of 10 during initialization. At this point it creates a memory location assigned on the local thread’s stack memory. When the value is printed it prints its value as 10.

    Now the same variable is passed to the function MethodUsingByVal by value. As soon as this method is called, a new memory location is called on the thread's stack for the variable intPara variable. Now whatever operation we do for the intPara, the changes are applied to the newly created memory location.

  • Passing Reference type by Value: The next scenario I want to explain here is, if a reference type is passed as a value then a copy of the reference is passed to the method not the reference itself. The following example can explain it better.
    1. static void Main(string[] args)    
    2. {         
    3.     MyClass intMyClass = new MyClass();    
    4.     intMyClass.LocalProperty = 10;    
    5.     Console.WriteLine(intMyClass.LocalProperty); //prints 10    
    6.     ValForReference(intMyClass); //prints 20    
    7.     Console.WriteLine(intMyClass.LocalProperty); //prints 20    
    8.     Console.Read();    
    9. }       
    10.  /// <summary>    
    11.  /// The method accepts the instance of MyClass type which is passed by value.    
    12.  /// </summary>    
    13.  /// <param name="myClass"></param>    
    14. public static void ValForReference(MyClass myClass)    
    15. {    
    16.     myClass.LocalProperty = 20;    
    17.     Console.WriteLine(myClass.LocalProperty);                       
    18. }    
    19.     
    20. public class MyClass    
    21. {       
    22.    public int LocalProperty { getset; }    
    23. }  
    In the preceding example I created a reference type (class) MyClass that has a property of integer type LocalProperty.

    I created an instance of the MyClass type, intMyClass, and assigned a value of 10 to the property. Now if I pass this variable (intMyClass) to the method ValForReference, a new variable is created on the thread’s stack that will contain an already existing reference (the reference contained by intMyClass). Any changes done to this reference variables will be visible outside the scope of this function.

    But since this is just a copy of the reference, not the original reference, the changes to the reference are not visible outside the method scope as shown in the following example.
    1. static void Main(string[] args)    
    2. {    
    3.         
    4.    MyClass intMyClass = new MyClass();    
    5.    intMyClass.LocalProperty = 10;    
    6.    Console.WriteLine(intMyClass.LocalProperty); //prints 10    
    7.    NullifyTheReference(intMyClass);     
    8.    Console.WriteLine(intMyClass.LocalProperty); //The reference is not null and still prints 20    
    9.    Console.Read();    
    10. }    
    11.   
    12. public static void NullifyTheReference(MyClass myClass)    
    13. {    
    14.    myClass.LocalProperty = 20;    
    15.    Console.WriteLine(myClass.LocalProperty);    
    16.    myClass = null// we are setting the myClass variable as null    
    17. }   

Pass By Reference

  • Passing value types by reference: Parameters to the methods can be passed as a reference by marking the parameters with the ref or out keywords in C#. With one of these two keywords, the reference of the variable is passed from the called function. That was not the case for the parameters if they are passed by value. I will explain the out and ref keywords later, first let me explain the parameter passing by reference.
    1. static void Main(string[] args)    
    2. {    
    3.    int localVar = 10;    
    4.    Console.WriteLine(localVar);//prints 10    
    5.    MethodUsingByReference (ref localVar);//prints 20    
    6.    Console.WriteLine(localVar);//prints 20    
    7.    Console.Read();     
    8. }    
    9. public static void MethodUsingByReference(ref int intPara)    
    10. {    
    11.      intPara = 20;    
    12.      Console.WriteLine(intPara);    
    13. }   
    As we can see from the preceding code snippet, the value type is passed as a reference and that means the memory location is passed to the method, due to which we can see the changes also at the caller functions variable, localVar, even after the control is returned from the called function.

  • Passing reference type by reference: Just like value types, reference types can also by passed by reference using the ref keyword. In other words, instead of creating a copy of the reference type, the reference itself is passed to the function.

    This is the main difference for reference types being passed as by val or by ref. Many people think that it doesn’t matter for reference types by whatever way they are passed but that is not the case.
    1.  static void Main(string[] args)    
    2.  {    
    3.    MyClass intMyClass = new MyClass();    
    4.    intMyClass.LocalProperty = 10;    
    5.    Console.WriteLine(intMyClass.LocalProperty); //prints 10    
    6.    NullifyTheReference(ref intMyClass);    
    7.   Console.WriteLine(intMyClass.LocalProperty); //Exception "Object reference not set to an instance of an object."        Console.Read();    
    8. }    
    9. public static void NullifyTheReference(ref MyClass myClass)    
    10. {    
    11.   myClass = null;    
    12. }    
    As we can see from the preceding code example, when we are nullifying the myClass variables reference, the effect is visible in the caller functions as “Object reference not set to an instance of an object.”. An exception is thrown.

    For that reason, we should use the ref keyword with caution since this can lead to subtle bugs in the code, that would be difficult to find. Please use the ref keyword for reference types with caution.

Explaining out and ref keywords

As I have already said, parameters can be passed to the function by ref using the two keywords out and ref. In this portion of the article I want to explain the main differences between these two keywords.

  1. The metadata emitted by the CLR for both of these keywords is the same, that in turn indicates that the parameter is passed by the reference no matter which keyword is used.

  2. The CLR treats both of these keywords as identical and that can be confirmed by my previous point, but that is not the case with the C# compiler that treats these keywords differently.

  3. If the parameter is marked as out then there is no need for the caller to initialize the variable. The called method is not expected to read from the parameter value without being initialized and the parameter cannot be returned without being initialized. If we are not initializing the parameter in the method, we will get the compile time error.

  4. If the method uses the ref keyword and is not initialized before being passed to the method then that expects the parameter passed by ref and we will get a compile time error stating “Use of uninitialized local variable”, which in other words we need to initialize the value before using it with the ref keyword.

  5. It is generally preferred to use the out keyword if the variable being created is a large value type or reference type.

  6. We can create overloaded methods based on the ref keyword and without the ref keyword as shown in the following code snippet.
    1. public static void NullifyTheReference(ref MyClass myClass)    
    2. {    
    3.        
    4. }    
    5.     
    6. public static void NullifyTheReference(MyClass myClass)    
    7. {    
    8.         
    9. }   
  7. On the other hand we cannot overload the methods based on the out and ref keywords since the CLR treats both of them as the same. The following code snippet is totally invalid and we will get a compile time error.
    1. public static void NullifyTheReference(ref MyClass myClass)    
    2.  {    
    3.         
    4.  }    
    5.   
    6.  public static void NullifyTheReference(out MyClass myClass)    
    7.  {    
    8.          
    9.  }   
  8. The variables passed by reference to the methods must be of the same type as of the parameter of the method, to ensure the type safety in .NET that I explained in one of my articles here.

    Before ending the article I would like to show the example of the out keyword
    1. static void Main(string[] args)    
    2. {    
    3.     MyClass myclassInst;    
    4.     UsingTheOut(out myclassInst);//using the uninitialized variable myclassInst    
    5.     Console.WriteLine(myclassInst.LocalProperty);//prints 10    
    6.     Console.ReadKey();    
    7. }    
    8.   
    9. public static void UsingTheOut(out MyClass myClass)    
    10. {    
    11.     myClass = new MyClass();    
    12.     myClass.LocalProperty = 10;    
    13. }   

This was an article about the ways parameters can be passed to methods in C#. Though these keywords can be easy to understand we should use them carefully and intelligently to avoid some undesirable results.


Similar Articles