A C# ref
-parameter is passed as a reference, not a value. This means we can assign the parameter in the called method and have it also be assigned at the calling site.
There is a difference between the ref
-keyword and the out
-keyword. We do not need to assign an initial value to ref
before passing it to a method.
This program defines the Program
class
with Main
and two other methods—SetString1
and SetString2
. The methods have formal parameter lists with ref
keywords.
ref
-keyword. Whenever we pass a string
to this method, it must have the ref
-keyword.out
-keyword. Whenever we want to call SetString2
, we must use the out
-keyword on its argument.string
parameter before sending it to SetString2
.using System; class Program { static void Main() { // Part 1: use ref argument. string value1 = "cat"; SetString1(ref value1); Console.WriteLine(value1); // Part 2: use out argument. string value2; SetString2(1, out value2); Console.WriteLine(value2); } static void SetString1(ref string value) { if (value == "cat") { Console.WriteLine("Is cat"); } value = "dog"; } static void SetString2(int number, out string value) { if (number == 1) { value = "one"; } else { value = "carrot"; } } }Is cat dog one
We can refactor code that acts upon multiple local variables or fields. We create a method with a ref
argument. And then we pass each separate variable to this method.
ref
argument in the NullIf
method both reads and writes the string
. It is an input and output argument.using System; class Program { static void Main() { string v1 = "dot"; string v2 = "net"; string v3 = "perls"; NullIf(ref v1); NullIf(ref v2); NullIf(ref v3); Console.WriteLine(v1); Console.WriteLine(v2); Console.WriteLine(v3); } static void NullIf(ref string value) { if (value == "net") { value = null; } } }dot perls
A method can return a reference to an argument or a local. This is useful if we want to modify the returned object, and have these modifications reflected in the current scope.
HigherValue
method. It compares the structs, and returns a reference to one of them.HigherValue
. We modify the returned struct
.Main
method. So the ref
return affects the local state of Main
.using System; struct Test { public int Value; } class Program { static ref Test HigherValue(ref Test left, ref Test right) { // Compares the two Test struct arguments. // ... Return a reference to the one with the higher value. if (left.Value > right.Value) { return ref left; } else { return ref right; } } static void Main() { Test t1; t1.Value = 10; Test t2; t2.Value = 20; // Get the struct with the higher value. // ... Then modify its value. HigherValue(ref t1, ref t2).Value = 30; // Display values of 2 structs. Console.WriteLine(t1.Value); Console.WriteLine(t2.Value); } }10 30
To use a ref
return to our advantage, a mutable struct
(or array) is needed. We can assign to the result of a method—this effect is reflected in the current method.
The ref
-keyword and out
-keyword can confuse the overload resolution step in the C# compiler. It can be a bad idea to mix these parameters in an interface
or object method group.
The ref
-keyword is sometimes used in methods that enhance performance—it can lead to simpler code. But often it makes code more complex and should be avoided.
The ref
-keyword allows us to pass variable references, as opposed to object references. The storage location of the variable itself is copied on the method invocations.