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
-
numberis initialized with10. -
ref numberpasses the variable by reference. -
UpdateValue()receives access to the original variable. -
The method changes its value to
20. -
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:
refis 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
-
resultis declared without initialization. -
out resultpasses the variable toCalculate(). -
The method calculates
10 + 20. -
The result
30is assigned tosum. -
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()returnstrueorfalseto indicate whether conversion succeeded. -
The converted integer is returned through the
outparameter. -
If parsing fails,
numberreceives0. -
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
outparameter before returning normally. -
Read Restriction: The method cannot read an
outparameter before assigning it. -
Multiple Outputs: Useful for returning additional values.
-
Syntax:
outis 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
-
numberis initialized with100. -
in numberpasses the variable by readonly reference. -
DisplayValue()can read the value. -
The method cannot reassign
value. -
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:
inis optional at the call site for ordinaryinparameters. -
Common Usage: Large structs, readonly data access, and performance-sensitive code.
4. Difference Between ref, out, and in
|
Feature |
|
|
|
|---|---|---|---|
|
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 |
|---|---|
|
|
Read and modify the original variable |
|
|
Assign and return a value through a parameter |
|
|
Readonly reference parameter |
|
|
Must initialize before calling |
|
|
Must assign inside the method |
|
|
Cannot reassign inside the method |
|
|
Swap two numbers |
|
|
|
|
|
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.