By default, arguments in C# are passed to functions by value. This means.

However, C# provides parameter modifiers (in, ref, and out) to enable passing arguments by reference, which can optimize performance, manage memory, and support advanced use cases like returning multiple values or modifying data in-place.

1. in Keyword

What does it mean?

A temporary variable will be created.

Use-cases

static void Main()
{
    MyStruct myStruct = new MyStruct { Value = 10 }; // Initialize MyStruct with Value = 10.

    Print(in myStruct); // ✅ Pass MyStruct by reference explicitly, no temporary created.
    Print(myStruct);    // ✅ Pass MyStruct by reference implicitly, no temporary.

    // Print(in myStruct.Value); // ❌ Compiler error: 'in' cannot be used with fields/properties.
    Print(myStruct.Value); // ⚠️ A Temporary created due to implicit int → double conversion.

    const int constantValue = 100; // Declare a constant integer.
    Print(constantValue);  // ⚠️ A Temporary created due to implicit int → double conversion.

    Print(myStruct.Value + 5); // ⚠️ A Temporary created as expression result is int → double.

    int num = 5;
    Print(num); // ⚠️ A Temporary created due to implicit int → double conversion.

    const double constantNum = 10;
    // Print(in constantValue); ❌ fails because constantValue is a constant.
    Print(constantNum); // ⚠️ A Temporary created for const due to 'in' parameter requirement.
}

// Using 'double' as an argument for simplicity; passing it as 'in' provides no benefit
// since 'double' is no larger than a reference.
static void Print(in double value)
{
    //
}

static void Print(in MyStruct data)
{
    //
}

Internal Codes

2. ref Keyword

Use Cases for the ref in Method Parameters.

MyStruct myStruct = new MyStruct { Value = 10 };

Print(ref myStruct); // ✅ Correct usage

// (CS9192) ⚠️ Compiler will raise warning: The argument 1 should be passed with ref or in
Print(myStruct);

// (CS0206) ❌ A non ref-returning property or indexer may not be used as an out or ref value
PrintValue(ref myStruct.Value);

static void PrintValue(ref int value) // For test purposes
{
    //
}

static void Print(ref readonly MyStruct data)
{
    //
}

public static class ExtensionMethods
{
    // (CS8333) ❌ Would raise error if first 'ref readonly', 'in' parameter is not a Value type
    // (CS8337) First 'ref' parameter must be a value type or a generic type constrained to struct
    public static void Print(this ref Point point)
    {
        //
    }
}

Endpoint

3. The out Keyword

Common Use-Cases

if (int.TryParse(input, out _)) // ✅ Correct usage
{
    //
}
else
{
    //
}

public bool TryImagineMethod(int x, int y, out MyStruct mystruct) // ✅
{
    // Initialize the struct
}

public static class MyExtensions
{
    // ❌ (CS8328): 'out' cannot be used with this.
    public static void ResetValue(this out int value)
    {
        //
    }
}

// ❌ (CS1741) A ref or out parameter cannot have a default value.
static void Calculate(out int data = 10)
{
    //
}

var myclass = new MyClass();
myclass.Value = 1;

// ❌ (CS0206) A ref or out parameter must be an assignable variable.
Calculate(out myclass.Value);

// ❌ (CS1510) A ref or out parameter must be an assignable variable.
Calculate(out numbers.First());

var numbers = new[] { 1, 2, 3 };
var query = from n in numbers
            select Calculate(out n); // ❌ (CS1939) Cannot pass range variable as ref, out

Example

Global rules: We can't use in, ref, or out in method parameters (compiler error CS1988).

async Task TestAsync(ref int x) // ❌ Not allowed
{
    await Task.Delay(100);
    x++;
}

IEnumerable<int> GetNumbers(ref int x) // ❌ Not allowed
{
    yield return x;
}

// ❌ (CS1988) Error: Async methods cannot have in, ref, out parameters.
async Task TestAsync(in MyStruct mystruct)
{
    //
}

// ❌ (CS1623) Iterator methods, which include a yield return or yield break statement,
// cannot have in, ref, out parameters.
IEnumerable<int> GetNumbers(in MyStruct x)
{
    yield return x.Value;
}

static void Print(ref MyStruct data)
{
    //
}

// ❌ (CS0663) Cannot define overloaded methods that differ only on ref, out, in.
static void Print(in MyStruct data)
{
    //
}

There are also some restrictions on Generics.

Thanks for reading!