CodeGym /Courses /C# SELF /Parameter Modifiers ( ref

Parameter Modifiers ( ref, out, in)

C# SELF
Level 12 , Lesson 4
Available

1. Introduction

In C#, by default, all method parameters are passed by value, meaning the method gets a copy, not the original.

But what if you need to change an external variable from inside a method? Or return several values from a method at once? Or maybe you want to pass a big struct into a method, but you don't want to copy that whole "suitcase with no handle"—you just want to pass a reference to save memory?

All of this is about parameter modifiers. They give you control over the "route" your data takes between the calling code and the method.

Types of Modifiers

Modifier Data Direction Need to initialize before call? Can read inside? Can write inside? Typical Usage Scenarios
ref Both ways Yes Yes Yes Pass a variable for reading and/or changing
out Only out No No (before assignment) Yes (required!) Return multiple values from a method
in Only in Yes Yes No Pass big structs for "read only" with memory savings

Don't worry, we're about to go through each one. It's way easier than it sounds.

2. Modifier ref: Pass by Reference: Read and Write

Imagine this: you bring your friend a cup of coffee and say—"Here, you can drink it, heat it up, or even add something to it." Your friend can do whatever they want with that coffee, and whatever's left (or not left) comes back to you. That's how ref works.


void DoSomething(ref int x)
{
    x = x + 10; // Changing the input parameter
}
        
Method with a ref parameter

To pass a parameter as ref, you have to declare it with that modifier both in the method and when calling it:

int myNumber = 5;
DoSomething(ref myNumber);
Console.WriteLine(myNumber); // prints 15

It has to be a variable, you can't pass an expression by reference. This code won't work:

DoSomething(ref 10);		// you need a variable here!
  • Before the call: the variable must be initialized (assigned a value).
  • Inside the method: you can read and change the value.
  • After the call: changes are saved.

Example: Swapping Variable Values

Sometimes you need to swap the values of two variables. But here's the catch: in C#, value types (like int) are passed by value by default. That means when you pass them to a method, their values are copied, not the references to the variables. For the method to change the actual variables in the calling code, you need to use the ref keyword.

Example without ref—doesn't work:

// Trying to swap values—won't work
void Swap(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}

int x = 10;
int y = 20;
Swap(x, y); // Passing value copies
Console.WriteLine($"{x}, {y}"); // → 10, 20 — nothing changed!

Inside the Swap function, the variables a and b are just copies of x and y. We're only changing those copies, the originals stay untouched.

Example with ref—variables actually swap


// Swapping variable values using ref
void Swap(ref int a, ref int b)
{
    int temp = a;
    a = b;
    b = temp;
}

int x = 10;
int y = 20;
Swap(ref x, ref y); // Passing variable references
Console.WriteLine($"{x}, {y}"); // → 20, 10 — swapped correctly
        

ref lets you pass references to the variables themselves, not just their values.
So the Swap function works directly with x and y, changing their contents.

When to use ref?

  • You need to change the passed variable (like increment it, replace it, etc.).
  • You don't need to return a new value (like with return), because you want to change the argument directly.
  • Don't use it to "dump" a bunch of different values—there's another modifier for that.

3. Modifier out: Passing Out

Now imagine: you come to your friend, but your cup is empty, and you ask: "Fill the cup—with whatever you want, coffee or tea!" After that, your friend has to fill it with something, or else the compiler will throw a fit.

out is made so a method can return several different values, skipping the return value. These parameters must be initialized inside the method.


void GetCoordinates(out int x, out int y)
{
    x = 5;
    y = 10; // Without this - error!
}
        
Method with out parameters
  • Before the call: the variable doesn't have to be initialized, you can even just write out int x in the call.
  • Inside the method: you must assign a value before exiting the method, or the compiler will go on strike.
  • After the call: the variable contains the new value.

Example: Returning Two Values from a Method

void ParseNameAndAge(string input, out string name, out int age)
{
    string[] parts = input.Split(',');	// turn the string into an array—split by ','
    name = parts[0];
    age = int.Parse(parts[1]);
}

string userInput = "Ivan,25";
ParseNameAndAge(userInput, out string userName, out int userAge);
Console.WriteLine($"{userName} — {userAge} years old");

When to use out?

  • When you need to return multiple values from a method (like splitting a string, as above).
  • When the return type isn't known in advance (like trying to convert a string to a number).

Examples from .NET: The int.TryParse(string, out int) method—classic!

string input = "123";
if (int.TryParse(input, out int parsedNumber))
{
    Console.WriteLine($"Converted: {parsedNumber}");
}
else
{
    Console.WriteLine("Conversion error!");
}

The int.TryParse method returns true if it managed to convert the string to a number, and false if it didn't. The actual number value is returned via out.

Common Mistakes and Funny Situations with ref and out

  • Forgot to initialize the variable for ref—the compiler gets mad.
  • Didn't assign a value for out—the compiler gets even madder.
  • Forgot to explicitly specify the modifier when calling: wrote DoSomething(x) instead of DoSomething(ref x).
  • Using ref or out with constants or literals is not allowed! Only variables. Only they have a memory address you can reference.

4. Modifier in: Read Only, and Only by Reference

Sometimes you need to pass a big, complex object into a method. Usually, such an object is passed by reference, but then it can be accidentally changed by the function, since it has full access—we gave it the reference.

In theory, you could make a full copy of your object and pass that. Then no one can change the original. But if the object is huge, you're just wasting memory copying all that data. It's way better to pass the object into the function and ask the compiler to make sure nobody changes it.

in is a new modifier that lets you pass structs by reference, but read-only. It's like "putting a precious sword on display behind glass": you can look, but you can't touch.


void PrintPoint(in Point pt)
{
    pt.X = 5; // Error! Read only.
    Console.WriteLine($"Point: {pt.X}, {pt.Y}");  //This is fine
}
        
Method with in parameter (read only)
  • Before the call: the variable must be initialized.
  • Inside the method: you can only read, not change.
  • Memory savings: the struct isn't copied, it's passed by reference.

Used, for example, for arrays of big structs, to avoid unnecessary copying. But with classes (reference types), in doesn't really do much.

Example: Passing a Big Struct by Reference to Avoid Copying

struct BigData
{
    public int A, B, C, D, E;
}

void PrintBigData(in BigData data)
{
    data.A = 10; // not allowed—read only!
    Console.WriteLine(data.A + data.B + data.C + data.D + data.E);
}

BigData myData = new BigData { A = 10, B = 20, C = 30, D = 40, E = 50 };
PrintBigData(in myData);

5. Frequently Asked Questions:

Can I use ref/out/in with arrays and reference types?
Yep! But remember: arrays themselves are already reference types. Passing an array with ref lets you change the reference itself. Most often, this is needed for structs.

What's the difference between ref and out if I can get a value in both cases?
With ref, the variable must be initialized before you use it. With out, it doesn't have to be, but inside the method it MUST be assigned at least once.

What if I try to use a literal (like the number 5) with ref/out/in?
The compiler will throw an error right away. Only variables!

How many parameters can I make ref/out/in?
As many as you want, no limits! Just don't go overboard for code readability: if you have more than two or three, maybe think about returning a tuple, struct, or class.

2
Task
C# SELF, level 12, lesson 4
Locked
Using the ref modifier
Using the ref modifier
2
Task
C# SELF, level 12, lesson 4
Locked
Using the out modifier
Using the out modifier
1
Survey/quiz
Classes and Objects, level 12, lesson 4
Unavailable
Classes and Objects
Intro to Inheritance
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION