Wednesday, July 20, 2022

Using in, out, and ref with Parameters in C#

 Introduction

In this guide, we will look at the difference between using inout, and ref when the passing reference and value types as parameters in C# methods. These techniques allow you to change how C# handles altering data locally in the method as well as outside the method.


The in, ref, and out Modifiers

Method parameters have modifiers available to change the desired outcome of how the parameter is treated. Each method has a specific use case:

  • ref is used to state that the parameter passed may be modified by the method.

  • in is used to state that the parameter passed cannot be modified by the method.

  • out is used to state that the parameter passed must be modified by the method.

Both the ref and in require the parameter to have been initialized before being passed to a method. The out modifier does not require this and is typically not initialized prior to being used in a method.


The ref Modifier

By default, a reference type passed into a method will have any changes made to its values reflected outside the method as well. If you assign the reference type to a new reference type inside the method, those changes will only be local to the method. See my Pluralsight guide Passing a Reference vs. Value for examples. Using the ref modifier, you have the option to assign a new reference type and have it reflected outside the method.

1class ReferenceTypeExample
2{
3  static void Enroll(ref Student student)
4  {
5    // With ref, all three lines below alter the student variable outside the method.
6    student.Enrolled = true;
7    student = new Student();
8    student.Enrolled = false;
9  }
10
11  static void Main()
12  {
13    var student = new Student
14    {
15      Name = "Susan",
16      Enrolled = false
17    };
18
19    Enroll(ref student);
20
21    // student.Name is now null since a value was not passed when declaring new Student() in the Enroll method
22    // student.Enrolled is now false due to the ref modifier
23  }
24}
25
26public class Student {
27  public string Name {get;set;}
28  public bool Enrolled {get;set;}
29}
csharp

Using the ref modifier, you can also change value types outside the method as well.

1class ReferenceTypeExample
2{
3  static void IncrementExample(ref int num)
4  {
5    num = num + 1;
6  }
7
8  static void Main()
9  {
10    int num = 1;
11    IncrementExample(ref num);
12    // num is now 2
13  }
14}
csharp

The out Modifier

Using the out modifier, we initialize a variable inside the method. Like ref, anything that happens in the method alters the variable outside the method. With ref, you have the choice to not make changes to the parameter. When using out, you must initialize the parameter you pass inside the method. The parameter being passed in often is null.

1class ReferenceTypeExample
2{
3  static void Enroll(out Student student)
4  {
5    //We need to initialize the variable in the method before we can do anything
6    student = new Student();
7    student.Enrolled = false;
8  }
9
10  static void Main()
11  {
12    Student student;
13
14    Enroll(out student); // student will be equal to the value in Enroll. Name will be null and Enrolled will be false.
15  }
16}
17
18public class Student {
19  public string Name {get;set;}
20  public bool Enrolled {get;set;}
21}
csharp

The out modifier works with value types as well. A useful example is using the out modifier to change a string to an int.

1int x;
2Int32.TryParse("3", out x);
csharp

The in Modifier

The in modifier is most often used for performance reasons and was introduced in C# 7.2. The motivation of in is to be used with a struct to improve performance by declaring that the value will not be modified. When using with reference types, it only prevents you from assigning a new reference.

1class ReferenceTypeExample
2{
3  static void Enroll(in Student student)
4  {
5    // With in assigning a new object would throw an error
6    // student = new Student();
7
8    // We can still do this with reference types though
9    student.Enrolled = true;
10  }
11
12  static void Main()
13  {
14    var student = new Student
15    {
16      Name = "Susan",
17      Enrolled = false
18    };
19
20    Enroll(student);
21  }
22}
23
24public class Student
25{
26  public string Name { get; set; }
27  public bool Enrolled { get; set; }
28}
csharp

Modifiers Are Not Allowed on All Methods

It's important to note that inout, and ref cannot be used in methods with the async modifier. You can use them in synchronous methods that return a task, though.

You cannot use them in iterator methods that have a yield return or yield break either.

Overloading Methods with Modifiers

When overloading a method in C#, using a modifier will be considered a different method signature than not using a modifier at all. You cannot overload a method if the only difference between methods is the type of modifier used. This will result in a compile error.