Ref, Out, In parameters in C#
Tags: programming, coding, csharp, dotnet
Published: 2023-06-15 09:08:02

> ℹ️ **Information**
> _The code in the following article was tested with C# 8 or above._

In C#, we have various techniques available for controlling the passing of arguments to methods. Among these, the keywords `ref`, `out`, and `in` play a particularly important role. These parameter modifiers allow you to specify the way data is transferred between methods, although they have some limitations.

## Ref

The `ref` keyword is used to pass an argument to a method by reference, rather than by value. This means that if a method changes the value of a `ref` parameter, this change will also be visible to the variable passed by the caller.

> 🔎 **Insight**
> _In <u>pass by value</u>, a copy of the actual parameter value is created and passed to the function. Any modifications made to the parameter inside the function do not affect the original value outside the function.
In <u>pass by reference</u>, the reference or memory address of the parameter is passed. Any modifications made to the parameter inside the function are reflected in the original value outside the function._

```csharp
public void SampleMethod(ref int x) 
{
    x = 10;
}

int num = 1;
SampleMethod(ref num);
Console.WriteLine(num); // Prints 10
```

It's important to highlight that to use a `ref` parameter, both the method definition and the calling method must explicitly use the `ref` keyword. Also, the variable passed as a `ref` parameter must be initialized before being passed to the method.

> ⚠️ **Warning**
> _Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by `ref` regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference._

## Out

The `out` keyword is used to pass arguments by reference. Unlike `ref`, however, `out` does not require that the input variable be initialized before being passed. Also, the method must necessarily assign a value to the `out` parameter before it concludes its execution.

```csharp
public void SampleMethod(out int x) 
{
    x = 10;
}

int num;
SampleMethod(out num);
Console.WriteLine(num); // Prints 10
```

> ⚠️ **Warning**
> _The `out` keyword can also be used with a generic type parameter to specify that the type parameter is covariant._

## In

The `in` keyword, introduced in C# 7.2, is used to pass an argument to a method by reference but prevents the value from being modified within the method. This is particularly useful when working with large structures, because it avoids the overhead of copying, while at the same time ensuring the integrity of the data.

```csharp
public void SampleMethod(in int x) 
{
    // x = 10; // This will generate an error
    Console.WriteLine(x);
}

int num = 1;
SampleMethod(in num); // Prints 1
```

> ⚠️ **Warning**
> _The `in` keyword can also be used with a generic type parameter to specify that the type parameter is contravariant, as part of a `foreach` statement, or as part of a `join` clause in a LINQ query._

## Limitations

Despite their usefulness, the keywords `ref`, `out`, and `in` have some limitations:

- They cannot be used in async methods defined with the `async` modifier.
- They cannot be used in iterator methods that include a `yield return` or `yield break` statement.
- The first argument of an extension method cannot have the `in` modifier unless that argument is a struct.
- They cannot be used in the first argument of an extension method in which that argument is a generic type, even when that type is constrained to be a struct.

The restrictions also extend to extension methods:

- The `out` keyword cannot be used in the first argument of an extension method.
- The `ref` keyword cannot be used in the first argument of an extension method, unless the argument is a struct or an unconstrained generic type.
- The `in` keyword cannot be used unless the first argument is a struct. Furthermore, it cannot be used in any generic type, even when it is constrained to be a struct.

Additionally, it's important to remember that members of a class cannot have signatures that differ only by `ref`, `in`, or `out`. In practice, a compiler error will occur if the only difference between two members of a type is that one of them has a `ref` parameter and the other has an `out` or `in` parameter.

> ⛔️ **Compiler Error [CS0663](https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0663)**
> _Cannot define overloaded methods that differ only on `ref` and `out`._

```csharp
public class TestClass
{
   public void SampleMethod(out int i) { }
   public void SampleMethod(ref int i) { }
}
```

Overloading is legal, however, if one method takes a `ref`, `in`, or `out` argument and the other has none of those modifiers, like this:

```csharp
public class TestClass1
{
    public void SampleMethod(int i) { }
    public void SampleMethod(ref int i) { }
}

public class TestClass2
{
    public void SampleMethod(int i) { }
    public void SampleMethod(out int i) => i = 5;
}

public class TestClass3
{
    public void SampleMethod(int i) { }
    public void SampleMethod(in int i) { }
}
```

## Conclusion

The `ref`, `out`, and `in` keywords provide detailed control over how arguments are passed to methods. Understanding and using them correctly can enhance code efficiency and safety. However, it's crucial to be aware of their limitations and use them cautiously, as improper use can render the code complex and hard to manage.

## References

- [ref](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref)
- [out parameter modifier](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier)
- [in parameter modifier](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier)