← Back to Articles         
Difference between ref, out, and in parameters

Difference between ref, out, and in parameters

Published on 12 Oct 2026     9 min read C#
C# Fundamentals
 

C# Method Parameters – Difference Between ref, out, and in

In C#, ref, out, and in are parameter modifiers that allow methods to work with variables by reference instead of receiving a normal value copy.

The main difference is whether the variable must be initialized before the method call and whether the method can modify its value.

1. What is the ref keyword in C#?

The ref keyword passes a variable by reference, allowing the called method to read and modify the original variable.

The variable must be initialized before passing it to the method.

Example

class Program
{
    static void Main()
    {
        int number = 10;

        UpdateValue(ref number);

        Console.WriteLine(number); // 20
    }

    static void UpdateValue(ref int value)
    {
        value = 20;
    }
}

Explanation

  1. number is initialized with 10.

  2. ref number passes the variable by reference.

  3. UpdateValue() receives access to the original variable.

  4. The method changes its value to 20.

  5. The modified value is available in Main().

How ref works

Main Method
-----------

int number = 10;
       |
       | ref number
       v
+-------------------------+
| UpdateValue(ref value)  |
|                         |
| value = 20;             |
+-------------------------+
       |
       v
Original variable updated
       |
       v
number = 20

Can we pass an uninitialized variable using ref?

No.

int number;

UpdateValue(ref number); // Compile-time error

Reason: A ref argument must be definitely assigned before the method call because the method is allowed to read its existing value.

Key Points

  • Pass by Reference: The method accesses the original variable.

  • Initialization: Required before the method call.

  • Read and Write: The method can read and modify the value.

  • Modification: Changes are reflected in the caller.

  • Syntax: ref is required in both the method declaration and normal method invocation.

  • Common Usage: Updating existing values, swapping variables, and modifying large structures without copying them.

 

2. What is the out keyword in C#?

The out keyword passes a variable by reference, primarily allowing a method to return an additional value through a parameter.

Unlike ref, the variable does not need to be initialized before the method call.

However, the method must assign a value to the out parameter before returning normally.

Example

class Program
{
    static void Main()
    {
        int result;

        Calculate(10, 20, out result);

        Console.WriteLine(result); // 30
    }

    static void Calculate(int a, int b, out int sum)
    {
        sum = a + b;
    }
}

Explanation

  1. result is declared without initialization.

  2. out result passes the variable to Calculate().

  3. The method calculates 10 + 20.

  4. The result 30 is assigned to sum.

  5. The caller receives the value through result.

How out works

Main Method
-----------

int result;  // Not initialized
       |
       | out result
       v
+---------------------------+
| Calculate(10, 20, out sum)|
|                           |
| sum = 10 + 20;            |
| sum = 30;                 |
+---------------------------+
       |
       v
Value assigned by method
       |
       v
result = 30

Can we use out to return multiple values?

Yes.

static void Calculate(
    int a,
    int b,
    out int sum,
    out int product)
{
    sum = a + b;
    product = a * b;
}

Usage:

Calculate(10, 20, out int sum, out int product);

Console.WriteLine(sum);     // 30
Console.WriteLine(product); // 200

Real-world example: int.TryParse()

One of the most common uses of out is the TryParse() method.

string input = "100";

bool success = int.TryParse(input, out int number);

Console.WriteLine(success); // True
Console.WriteLine(number);  // 100

Explanation:

  • TryParse() returns true or false to indicate whether conversion succeeded.

  • The converted integer is returned through the out parameter.

  • If parsing fails, number receives 0.

  • It avoids throwing a format exception for invalid input.

Key Points

  • Pass by Reference: The method can assign a value to the caller's variable.

  • Initialization: Not required before calling the method.

  • Mandatory Assignment: The method must assign the out parameter before returning normally.

  • Read Restriction: The method cannot read an out parameter before assigning it.

  • Multiple Outputs: Useful for returning additional values.

  • Syntax: out is required in the method declaration and normal invocation.

  • Common Usage: TryParse(), TryGetValue(), and methods returning success status with an output value.

 

3. What is the in keyword in C#?

The in keyword passes a variable by readonly reference.

The called method can read the value but cannot reassign the parameter.

It is useful when passing large value types, such as structures, without copying the entire value.

Example

class Program
{
    static void Main()
    {
        int number = 100;

        DisplayValue(in number);

        Console.WriteLine(number); // 100
    }

    static void DisplayValue(in int value)
    {
        Console.WriteLine(value);

        // value = 200; // Compile-time error
    }
}

Explanation

  1. number is initialized with 100.

  2. in number passes the variable by readonly reference.

  3. DisplayValue() can read the value.

  4. The method cannot reassign value.

  5. The original variable remains unchanged by this method.

How in works

Main Method
-----------

int number = 100;
       |
       | in number
       v
+--------------------------+
| DisplayValue(in value)   |
|                          |
| Read value  -> Allowed   |
| value = 200 -> Not Allowed|
+--------------------------+
       |
       v
Original variable remains
       |
       v
number = 100

Example with a structure

public struct Employee
{
    public int Id;
    public decimal Salary;
}

static void DisplayEmployee(in Employee emp)
{
    Console.WriteLine(emp.Id);
    Console.WriteLine(emp.Salary);

    // emp.Id = 200; // Compile-time error
}

Usage:

Employee emp = new Employee
{
    Id = 101,
    Salary = 50000
};

DisplayEmployee(in emp);

Why use in here?

Normally, passing a struct by value copies its contents. Using in passes it by readonly reference, which can reduce copying overhead for sufficiently large structures.

For small types such as int, using in usually provides no performance benefit.

Important: For ordinary in parameters, the in keyword at the call site is optional. Also, in does not guarantee deep immutability. If the parameter references a mutable object, that object's state may still be changed.

Key Points

  • Readonly Reference: Passes a variable by reference with restrictions on modification.

  • Initialization: Required before the method call.

  • Read: Allowed.

  • Reassignment: Not allowed inside the method.

  • Performance: Can reduce copying when passing large structures.

  • Call Syntax: in is optional at the call site for ordinary in parameters.

  • Common Usage: Large structs, readonly data access, and performance-sensitive code.

 

4. Difference Between ref, out, and in

Feature

ref

out

in

Passing mechanism

By reference

By reference

By readonly reference

Initialization before call

Required

Not required

Required

Can read inside method

Yes

After assignment

Yes

Can assign inside method

Yes

Yes

No

Must assign inside method

No

Yes

No

Changes visible to caller

Yes

Yes

No direct reassignment

Keyword at call site

Required

Required

Usually optional

Main purpose

Modify existing value

Return additional value

Avoid copies with readonly access

5. Complete Example – All Three Together

class Program
{
    static void Main()
    {
        // REF
        int a = 10;
        Update(ref a);
        Console.WriteLine(a); // 20

        // OUT
        int b;
        Calculate(out b);
        Console.WriteLine(b); // 100

        // IN
        int c = 50;
        Display(in c);
        Console.WriteLine(c); // 50
    }

    static void Update(ref int value)
    {
        value = 20;
    }

    static void Calculate(out int value)
    {
        value = 100;
    }

    static void Display(in int value)
    {
        Console.WriteLine(value);
    }
}

Execution flow

                C# Parameters
                      |
          +-----------+-----------+
          |           |           |
          v           v           v
         ref         out          in
          |           |           |
          v           v           v
    Read & Write  Assign Output  Read Only
          |           |           |
          v           v           v
    Must Initialize  No Initial  Must Initialize
      Before Call     Value       Before Call
          |           |           |
          v           v           v
      Update Value  Return Value  Protect Parameter
 

6. Important Interview Scenarios

Scenario 1: Swapping two numbers using ref

static void Swap(ref int a, ref int b)
{
    int temp = a;
    a = b;
    b = temp;
}

Usage:

int x = 10;
int y = 20;

Swap(ref x, ref y);

Console.WriteLine(x); // 20
Console.WriteLine(y); // 10

Why ref? Because the method must modify both original variables.

Scenario 2: Returning multiple values using out

static void GetEmployee(
    out int id,
    out string name)
{
    id = 101;
    name = "John";
}

Usage:

GetEmployee(out int id, out string name);

Console.WriteLine(id);   // 101
Console.WriteLine(name); // John

Why out? Because the method needs to provide multiple output values.

Scenario 3: Passing a large struct using in

public struct ReportData
{
    public decimal Total;
    public decimal Tax;
    public decimal Discount;
    public decimal NetAmount;
}

static void PrintReport(in ReportData report)
{
    Console.WriteLine(report.NetAmount);
}

Why in? Because the method only needs to read the struct, and passing it by readonly reference can avoid copying its contents.

 

7. Important Interview Follow-up Questions

Q1. What is the main difference between ref and out?

ref requires initialization before the method call, whereas out does not. An out parameter must be assigned by the called method before normal return.

Q2. Can we use ref without initializing a variable?

No. The variable must be initialized before passing it using ref.

Q3. Can we use out without initializing a variable?

Yes. The called method is responsible for assigning its value.

Q4. Can we modify an in parameter?

No. The method cannot reassign the parameter or directly modify its value-type fields. However, referenced mutable objects may still be modified.

Q5. Can ref be used with reference types?

Yes.

static void ChangeName(ref string name)
{
    name = "David";
}

Here, ref allows the method to change the caller's string reference.

Q6. Can we overload methods using only ref and out?

No. C# does not allow two overloads that differ only by ref versus out.

Q7. Does in improve performance in every situation?

No. It is primarily useful for sufficiently large value types. For small types, it may provide no benefit and can sometimes introduce additional overhead.

Q8. Can we use ref, out, and in in async methods?

Ordinary async methods cannot declare ref, out, or in parameters. Instead, return a value, tuple, or result object.

 

Quick Interview Revision

Keyword

Remember

ref

Read and modify the original variable

out

Assign and return a value through a parameter

in

Readonly reference parameter

ref

Must initialize before calling

out

Must assign inside the method

in

Cannot reassign inside the method

ref example

Swap two numbers

out example

int.TryParse()

in example

Pass a large struct without copying

Interview Answer:

ref, out, and in are parameter modifiers used to pass variables by reference in C#. ref allows a method to read and modify an already initialized variable. out allows a method to assign and return a value without requiring initialization by the caller. in passes a variable by readonly reference, preventing reassignment inside the method and potentially improving performance when passing large value types.

← Back to Articles