‘ref’ & ‘out’ keywords are very popular & useful in C# and some more enhancement has been done for ref & out in C# 7. I am going to explain all the basic concepts & usage of ‘ref’ and ‘out’ keywords along with the following 3 topics which are part of C# 7.
- ref returns
- ref Locals
- Inline out variable declaration (Declaring out variable directly while passing it as parameter.)
If you are looking for any other C# 7 features apart from the preceding 3 new enhancements, then you can visit the following articles on C# 7 which will help you to understand C# 7 in more detail.
- Top 10 New Features of C# 7 With Visual Studio 2017
- Visual Studio 15 Preview First Look & C# 7
- How to Compile & Test C# 7 Features
All the three concepts ‘ref returns’, ‘ref Locals’ & ‘Inline out variable declaration’ can be consolidated in a small program as shown in the following screen shot.
But before discussing C# 7 features I am going to explain basic concepts of ref & out.
Some basics concepts about ref and out
- ref and out both are passed as reference.
- out: Only for output not for input. It means we cannot pass a variable value as input using out parameter.
- ref: For input and output both. It means a variable passed with ref keyword can be used for input and output purposes as well.
- ref variable must be initialization before passing it as parameter.
- Out variable do not require initialization even if out variable is initialized before passing it as parameter then that initialization value cannot be accessed inside the method for which it has been passed as out variable.
- It is not necessary to manipulate the ref variable i.e. if a method is accepting a parameter with ref keyword it is not necessary to manipulate the ref variable before leaving the control.
- The method which is accepting a parameter as out must assign the value of ‘out’ parameter before leaving the control. In C# 7
- There is no need to declare out variable before passing it as argument (inline out variable declaration).
- A method can return a variable as reference (ref return)
- we can use ‘ref’ keyword with local variables which is known as ref locals.
Now I am going to prove each statement by examples
ref and out both are passed as reference.
Code Snippet
- static void Main(string[] args)
- {
- int x, y =0;
- DoSomething(out x, ref y);
- WriteLine($"x: {x} \ny: {y}");
- }
-
- public static void DoSomething(out int x, ref int y)
- {
- x = 10;
- y = 20;
- }
Output
x: 10
y: 20
As you can see in the preceding code snippet that whatever changes have been made to the variables x & y inside the method DoSomething() is also being reflected outside. Thus it proves that (ref & out) both are passed as reference.
out - Only for output not for input.
It means we cannot not pass a variable value as input using out parameter.
Code Snippet 1
- static void Main(string[] args)
- {
- int x = 20;
- DoSomething(out x);
- WriteLine($"Value of x is :{x}");
- }
- public static void DoSomething(out int x)
- {
-
- x += 10;
- }
Compiler Error: “Use of unassigned out parameter 'x'”
If I change ‘out’ parameter to ‘ref’ parameter then see what will happen
Code Snippet 2
- static void Main(string[] args)
- {
- int x = 20;
- DoSomething(ref x);
- WriteLine($"Value of x is :{x}");
- }
- public static void DoSomething(ref int x)
- {
- x += 10;
- }
Output
Value of x is :30
In the following code snippet, I am going to remove ‘ref’ keyword.
Code Snippet 3
- static void Main(string[] args)
- {
- int x = 20;
- DoSomething(x);
- WriteLine($"Value of x is :{x}");
- }
- public static void DoSomething(int x)
- {
- x += 10;
- }
Output
Value of x is :20
Code Snippet 4
- static void Main(string[] args)
- {
- int x = 20;
- DoSomething(out x);
- WriteLine($"Value of x is :{x}");
- }
- public static void DoSomething(out int x)
- {
- x = 10;
- }
Output
Value of x is :10
So “code snippet 1” & “code snippet 4” proves that ‘out’ is Only for output not for input.
ref: For input and output both.
A variable passed with ref keyword can be used for input and output purposes as well.
Code Snippet
- static void Main(string[] args)
- {
- int x =20;
- DoSomething(ref x);
- WriteLine($"Value of x is :{x}");
- }
- public static void DoSomething(ref int x)
- {
- WriteLine($"Value of x is :{x}");
- x += 10;
- }
Output
Value of x is :20
Value of x is :30
ref variable must be initialization before passing it as parameter.
Code Snippet 1
- static void Main(string[] args)
- {
- int x;
- DoSomething(ref x);
- WriteLine($"Value of x is :{x}");
- }
- public static void DoSomething(ref int x)
- {
-
- }
Compiler Error: “Use of unassigned local variable 'x'”
Code Snippet 2
- static void Main(string[] args)
- {
- int x=55;
- DoSomething(ref x);
- WriteLine($"Value of x is :{x}");
- }
- public static void DoSomething(ref int x)
- {
-
- }
Build Status - Successful
So, the preceding 2 code snippet proves that ‘ref’ variable must be initialization before passing it as parameter.
Out variable do not require initialization
Out variable does not require initialization even if out variable is initialized before passing it as parameter then that initialization value cannot be accessed inside the method for which it has been passed as out variable.
It is not necessary to manipulate the ref variable.
If a method is accepting a parameter with ref keyword it is not necessary to manipulate the ref variable before leaving the control.
The out parameter must be assigned to before control leaves the current method
The method which is accepting a parameter as out must assign the value of ‘out’ parameter before leaving the control.
inline out variable declaration
There is no need to declare out variable before passing it as argument and it can be declared inline. This is a new feature in C# 7. Following is a screenshot for the same which explain the difference between C# 6 & C# 7 coding style for inline out variable.
If you look at the preceding screenshot closely then you will find that it is showing 3 dots just below the ‘int’ keyword. The 3 dots are saying something and if you open the quick action you will get the suggestion that “variable can be declared inlined”.
After fixing this the code snippet
- int result;
- Add(10, 20, out result);
Will be changed to
- Add(10, 20, out int result);
So, in Visual studio 2017 support for inline variable declaration has been added and it also provides intellisence for inline variable declaration with information id “IDE0018”.
This inline variable will work with all the methods of C# which is accepting out parameter. Even though in-built methods of C# e.g. “DateTime.TryParse” will allow inline variable declaration. Following screenshot compare the code snippet of C# 6 & C# 7.
ref return
A method can return a variable as reference (ref return)
In C# 7 we can use ‘ref’ for return a variable from a method i.e. a method can return variable with reference.
Sample Code
- int[] x = { 2, 4,62,54,33,55, 66,71,92};
-
- public ref int GetFirstOddNumber(int[] numbers)
- {
- for (int i = 0; i < numbers.Length; i++)
- {
- if (numbers[i]%2==1)
- {
- return ref numbers[i];
- }
- }
- throw new Exception("odd number not found");
- }
But there are some restrictions and everything cannot be returned as reference like below code will give error,
- Dictionary<int, decimal> ProductPriceList = new Dictionary<int, decimal>();
- public ref decimal GetProductPriceReference(int productId)
- {
- return ref ProductPriceList[productId];
- }
Error
CS8156 An expression cannot be used in this context because it may not be returned by reference
You may be thinking what is the need of ‘ref return’. It can be achieved with ref return also. Let me explain it with some more examples:
ref locals
we can use ‘ref’ keyword with local variables which are known as ref locals.
As you have seen in the previous example, I am searching for an odd number inside an integer array and if it is not found then it's throwing an exception. The method is not returning it as value but as reference. So, you need to store that value also which has been returned as reference. To store it in a local variable we can use ‘ref’ keyword with local variables which is known as ref locals.
Code snippet
- int[] x = { 2, 4, 62, 54, 33, 55, 66, 71, 92 };
- ref int oddNum = ref GetFirstOddNumber(x);
Complete Code
- using static System.Console;
- namespace RefReturnsAndRefLocals
- {
- class Program
- {
- public ref int GetFirstOddNumber(int[] numbers)
- {
- for (int i = 0; i < numbers.Length; i++)
- {
- if (numbers[i] % 2 == 1)
- {
- return ref numbers[i];
- }
- }
- throw new Exception("odd number not found");
- }
- static void Main(string[] args)
- {
- Program p = new Program();
- int[] x = { 2, 4, 62, 54, 33, 55, 66, 71, 92 };
- ref int oddNum = ref p.GetFirstOddNumber(x);
- WriteLine($"\t\t\t\t{oddNum}");
- oddNum = 35;
- for (int i = 0; i < x.Length; i++)
- {
- Write($"{x[i]}\t");
- }
- ReadKey();
- }
- }
- }
output
In the above screenshot, you can see that first time the variable “OddNum” is storing the value 33 with its reference inside the array ‘x’.
If you print “oddNum” first time, then it will print 33 but after that I have re-assigned its value and set “oddNum =35” now iterating the array and printing elements of array and you can see that whatever I have done modification for “oddNum” from outside is also reflecting inside the array and internal value has been modified from 33 to 35.
Method with ref return can be used as left hand side statement
If a method is using ref return in that case, we can put it left hand side in a statement whereas method without ref return cannot be used as left hand side of statement.
Complete Code for method without ref return
- using static MethodWithoutRefReturn.DummyEmployees;
- namespace MethodWithoutRefReturn
- {
- class Program
- {
- static void Main(string[] args)
- {
- GetEmployee() = new Employee { Id = 2, Name = "Banketeshvar", Age = 28 };
- }
- }
-
- class Employee
- {
- public int Id { get; set; }
- public string Name { get; set; }
- public int Age { get; set; }
- }
-
- class DummyEmployees
- {
- public static Employee employee = null;
- public static Employee GetEmployee()
- {
- if (employee == null)
- {
- employee = new Employee { Id = 1, Name = "Manish Sharma", Age = 27 };
- }
- return employee;
- }
- }
- }
Complete Code for method with ref return
- using static MethodWithRefReturn.DummyEmployees;
- namespace MethodWithRefReturn
- {
- class Program
- {
- static void Main(string[] args)
- {
- GetEmployee() = new Employee { Id = 2, Name = "Banketeshvar", Age = 28 };
- }
- }
-
- class Employee
- {
- public int Id { get; set; }
- public string Name { get; set; }
- public int Age { get; set; }
- }
-
- class DummyEmployees
- {
- public static Employee employee = null;
- public static ref Employee GetEmployee()
- {
- if (employee == null)
- {
- employee = new Employee { Id = 1, Name = "Manish Sharma", Age = 27 };
- }
- return ref employee;
- }
- }
- }
Apart from the above explained point about ref and out you can find more about ref & out in the following article,