Ref Vs. Out Parameter In C#

Introduction

 
Hello folks,
 
As programmers, we come across methods/functions within the day or 2 of learning coding. I believe you are familiar with methods/functions in C#. The method may or may not return a value. But if they do return a value, they are restricted to one value. They can not return more than one value. Of course, we can use tuple in this case but again you have to store a result of a method in a tuple type only. Then access the tuple using item1 & item2. That's too complicated.
 
So there is another way to deal with this situation...
  • We can simply use ref or out parameters when the method wants to return more than 1 value.
  • Also in the scenario where we want to modify the parameter and send back the updated parameter to the caller.
Now let's understand the difference between pass by value & pass by reference.
  • Pass by Value
    When you pass an argument to a method as a value, the compiler creates a new memory location for that variable, and any changes made to that value will be stored on this new memory location. So the actual variable which we sent as an argument while calling a method will have no impact or whatsoever as it is still stored on an old memory location.

  • Pass by Reference
    Here, when we pass an argument to a method as a reference, we actually pass the memory location of that variable rather than passing the value of the variable. Now if we make any changes to that parameter, it will also be reflected in the original variable as we are updating the reference, not the value.
We will get a better understanding of their behavior with a live example.
  • Define a base price in double.
  • Then let's have 2 methods:

    • GetGST_AffectedPrice
      It will add 18% GST to the base price.

    • GetGST_AffectedPriceWithRef
      Even this will add 18% GST to base price, but with ref parameter.
      1. using I_Cant_See_Sharp.Apple;    
      2. using System;    
      3.     
      4. namespace I_Cant_See_Sharp    
      5. {    
      6.     class Program    
      7.     {    
      8.         static void Main(string[] args)    
      9.         {    
      10.             double basePrice = 15000;    
      11.              
      12.             Console.WriteLine("---------- Pass by value ------------");    
      13.             Console.WriteLine("Price before GST: "+ basePrice);    
      14.             GetGST_AffectedPrice(basePrice);    
      15.             Console.WriteLine("Price after GST: " + basePrice);    
      16.     
      17.             Console.WriteLine(Environment.NewLine);    
      18.     
      19.             Console.WriteLine("----------   Pass by ref ------------");    
      20.             Console.WriteLine("Price before GST: " + basePrice);    
      21.             GetGST_AffectedPriceWithRef(ref basePrice);    
      22.             Console.WriteLine("Price after GST: " + basePrice);    
      23.         }    
      24.     
      25.         static void GetGST_AffectedPrice(double basePrice)    
      26.         {    
      27.             basePrice += (0.18 * basePrice);    
      28.         }    
      29.         static void GetGST_AffectedPriceWithRef(ref double basePrice)    
      30.         {    
      31.             basePrice += (0.18 * basePrice);    
      32.         }    
      33.     }    
      34. }    
Let's see how the compiler treated the ref parameter.
 
 
As per the output, only the ref parameter's value changed.
 
NOTE
The object type is a reference type, i.e. even if you don't mention a ref keyword, the compiler still treats it as a ref parameter.
 
Let's see this in action: say we have a Phone class & we are trying to update its price with 2 methods, one which has a ref parameter & another one without the ref parameter. 
  1. using I_Cant_See_Sharp.Apple;  
  2. using System;  
  3.   
  4. namespace I_Cant_See_Sharp  
  5. {  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         {  
  10.             Phone IPhone = new Phone() { Name = "XR", OS = "IOS 14" };  
  11.             Console.WriteLine("---------------------------------------------- Pass by value ------------------------------------------------");  
  12.             Console.WriteLine("IPhone's price Pass By Value: "+ IPhone);  
  13.             GetPhonePrice(IPhone);  
  14.             Console.WriteLine("IPhone's price after Pass By Value: "+ IPhone);  
  15.   
  16.             Console.WriteLine(Environment.NewLine);  
  17.             Phone IPhone2 = new Phone() { Name = "XR", OS = "IOS 14" };  
  18.             Console.WriteLine("----------------------------------------------   Pass by ref ------------------------------------------------");  
  19.             Console.WriteLine("IPhone's price Pass By Ref: " + IPhone2);  
  20.             GetPhonePriceWithRef(ref IPhone2);  
  21.             Console.WriteLine("IPhone's price after Pass By Ref: " + IPhone2);  
  22.   
  23.         }  
  24.   
  25.         static void GetPhonePrice(Phone Phone)  
  26.         {  
  27.             Phone.Price = 60000;  
  28.         }  
  29.         static void GetPhonePriceWithRef(ref Phone Phone)  
  30.         {  
  31.             Phone.Price = 60000;  
  32.         }  
  33.     }  

Let's see if we are correct in this case or not:

 
It worked as expected!
 
In C# we pass ref & out parameter as a reference, not as a value.
 
Remember, In the example of calculating GST, we used a basePrice variable as a ref parameter, we have already initialized the value of a basePrice & then we passed it to a method.
 
What if don't initialize the value first & we pass it to a method?

 
We have a compile-time error: which is not allowing us to pass the unassigned variable.
 
In order to overcome this, we have an out parameter.
 
out parameter
  • But there is one catch, if we do not initialize the variable basePrice before calling a method but we kinda need the actual value of basePrice to apply GST on. So it is compulsory to initialize basePrice inside a method.

    • Out parameter is used when it is not necessary to initialize the variable outside of a method
  1. class Program  
  2.   {  
  3.       static void Main(string[] args)  
  4.       {  
  5.           double basePrice;  
  6.            
  7.           Console.WriteLine("----------   Pass by out ------------");  
  8.           GetGST_AffectedPriceWithOut(out basePrice);  
  9.           Console.WriteLine("Price after GST: " + basePrice);  
  10.       }  
  11.   
  12.        
  13.       static void GetGST_AffectedPriceWithOut(out double basePrice)  
  14.       {  
  15.           basePrice = 15000;  
  16.           basePrice += (0.18 * basePrice);  
  17.       }  
  18.   } 
Let's see if this works or not:
 
 
Works, Fine!
 
Let's not initialize the variable inside a method, will we able to proceed?
 
 
The answer is No, we got a compile-time error: unable to use the unassigned out parameter.
 
So we always need to initialize an out parameter inside a method before using it.
 
But it is only applicable to the primitive data types.
 
Let's see a real-time example of out parameter for the object type,
  • Say we have Phone's object. Now we need to fetch details for this object which is only possible by calling some API.
  • In this scenario, we won't initialize an object of a phone before calling an API as we wouldn't know the outcome of the API before calling it.
  • But you can not send an unassigned variable to the method.
  • So the solution here is the out parameter.

    • We don't need to initialize it before
    • And we can initialize inside a method after calling its API
    • Plus, the result can be reflected in the outside parameter, the method does not need to explicitly return a Phone's initialized object.
  1. using I_Cant_See_Sharp.Apple;  
  2. using System;  
  3.   
  4. namespace I_Cant_See_Sharp  
  5. {  
  6.     class Program  
  7.     {  
  8.       
  9.         static void Main(string[] args)  
  10.         {  
  11.             //APIResult will only be initialized after API Call  
  12.             //So there is no way to get the details at this point  
  13.             Phone APIResult;  
  14.             //need to use out parameter as ref parameter needs to be initialize   
  15.             //even normal parameter has to be initialized before calling a method.  
  16.             GetPhoneDetails(out APIResult);  
  17.         }  
  18.   
  19.        /// <summary>  
  20.        /// Get Phone details  
  21.        /// </summary>  
  22.        /// <param name="APIResult"></param>  
  23.         static void GetPhoneDetails(out Phone APIResult)  
  24.         {  
  25.             //Heavy API Call  
  26.             //Phone variable gets initilize after a API call, and value gets reflected in the out parameter   
  27.             APIResult = WebAPI.GetCall("localhost:/api/GetPhoneDetails");  
  28.         }  
  29.     }  
  30. }  
Let's note down the difference we learned so far:
 
Ref Parameter
Out Parameter
It must be initialized before passing it to the method
Works with uninitialized or initialized variables
The ref parameter doesn't need to assign itself inside a method as we have passed assigned variable to a method. But it is optional, the variable can be re-assigned.
It is compulsory to assign the out parameter inside a method as we have not initialized the variable while passing it to a method.
value can be updated, but it is optional. as variable already has value, it is up to the requirements whether to modify value inside a method or not.
we pass uninitialized out parameter to a method, which has to be initialized inside a method. so becomes a compulsion.
 

Conclusion

 
Ref & Out both parameters have the same concept, but they are differently executed or treated by the compiler.
  • Ref parameter is used when we want to modify the value of a parameter
  • Out parameter is used when we expect the method to always return a value (out param) with an initialized variable.