Introduction
C# 7.0 introduces ref returns and ref locals. The main goal of these new features is to make it easier for developers to pass around references to value types instead of copies of their values. This is important when working with large data structures that are implemented as value types.
C# allows passing parameters by reference, but a method was not able to return a reference. This has been changed with C# version 7.0.
Current ref and out approach
We can use ref and out arguments for sending some variables to the method and let it modify the value of this method. This way we can write methods that “return” more than one value. Ref lets the value type in by reference. Out means that the variable will get a value in the method where it is given as an argument.
- class Program {
- static void Main(string[] args) {
- string fName = string.Empty;
- string lName;
- GetFirstName(ref fName);
- Console.WriteLine($ "FirstName : {fName}");
- GetLastName(out lName);
- Console.WriteLine($ "Last Name : {lName}");
- Console.ReadLine();
- }
- static void GetFirstName(ref string fName) {
- fName = "Prasad";
- }
- static void GetLastName(out string lName) {
- lName = "Raveendran";
- }
- }
In the example above, you can see the differences between ref and out keywords in action. In the first few lines, we assign a value to fName but not lName, because fName will be passed through an argument using the ref keyword, meaning that an initial value must be assigned to it. The out keyword value (lName) isn’t defined until the called method towards the end of the code, because it must be defined in the called method before being passed to the calling method.
Ref Return
A method that returns a reference return value must satisfy the following two conditions:
- The method signature includes the ref keyword in front of the return type.
- Each return statement in the method body includes the ref keyword in front of the name of the returned instance.
- public class RefReturn {
- private int value = 10;
- public ref int Get() {
- return ref this.value;
- }
- public void Display() {
- Console.WriteLine($ "RefReturn : {this.value}");
- }
- }
In this example, the Get method in RefReturn returns the private field value by reference. If value were read-only, the compiler would not permit it to be returned by reference.
Ref Local
To store a reference into a local variable, define the local variable as a reference by adding the keyword ref before the variable type and add the keyword ref before the method call.
- class Program {
- static void Main(string[] args) {
- REfLocalAndReturnTest();
- Console.ReadKey();
- }
- public static void REfLocalAndReturnTest() {
- var refReturn = new RefReturn();
- ref int _reflocal = ref refReturn.Get();
- int local = refReturn.Get();
- refReturn.Display();
- Console.WriteLine($ "RefLocal: {_reflocal}");
- Console.WriteLine($ "Local: {local}");
- _reflocal = 10;
- local = 20;
- change(_reflocal);
- refReturn.Display();
- Console.WriteLine($ "RefLocal: {_reflocal}");
- Console.WriteLine($ "Local: {local}");
- }
- public static void change(int value) {
- value = 30;
- }
- }
Output
REfReturn : 10
RefLocal: 10
Local: 10
REfReturn : 10
RefLocal: 10
Local: 20
From the output, we see that _reflocaldoes indeed reference the private variable refReturn.value, as its value has changed too. Whereas localcontains a copy, as changing its value has no effect on refReturn.value. Finally, the call to change shows that when ref locals are accessed without the refkeyword, they behave just like normal locals and are passed by value to other methods.
Other Uses
Referencing Array Elements
It is possible to return a reference to arrays.
Please find the example below, we are trying to modify the character array:
- public static void ReferrencingArrayElement() {
- char[] values = {
- 'A',
- 'E',
- 'B',
- 'O',
- 'U'
- };
- Console.WriteLine($ "Before : {string.Join(", ", values)}");
- ref char value = ref ReplaceNonVowel(values);
- value = 'I';
- Console.WriteLine($ " After :{string.Join(", ", values)}");
- }
- public static ref char ReplaceNonVowel(char[] array) {
- return ref array[2];
- }
Output
Before : A,E,B,O,U
After :A,E,I,O,U
Referencing Local Variables
We can also reference other local variables:
- public static void ReferencingLocalVariable() {
- int age = 10;
- ref int changeAge = ref age;
- Console.WriteLine($ "Before: age= {age} and changeAge={changeAge}");
- changeAge = 20;
- Console.WriteLine($ "After: age= {age} and changeAge={changeAge}");
- }
Output
Before: age= 10 and changeAge=10
After: age= 20 and changeAge=20
In the upcoming tutorials, we will be discussing:
- Local Functions
- Pattern Matching
- Improved Features,
- Expression-Bodied Members,
- throw Expressions,
- Numeric Literals,
- Out Parameters -> Out Variables
- Out Wildcards