Skip to content
Theory · Value and reference types · lesson 4 of 11

An object as a parameter

In the previous theme, the method Repaint repainted the house passed to it: the parameter got a copy of the reference. It is like sending a colleague a link to a cloud document: they can edit the document through it, but they cannot replace the link you hold.

The method changes the object

Let's recall this with a method that tops up a bank account:

C#
Account acc = new Account();
acc.Balance = 100;
Deposit(acc);
Console.WriteLine(acc.Balance); // 150

void Deposit(Account a)
{
    a.Balance = a.Balance + 50;
}

class Account
{
    public int Balance;
}

Let's go through the example line by line:

  1. Deposit(acc) copies the reference from acc into the parameter a. There is still one object.
  2. a.Balance = a.Balance + 50 follows the reference and changes a field of that shared object.
  3. After the call, acc.Balance prints 150: the method and the caller worked with one account.

A new object in the parameter

Now the method tries to "reset" the account by putting a new object into the parameter:

C#
Account mine = new Account();
mine.Balance = 100;
Reset(mine);
Console.WriteLine(mine.Balance); // 100

void Reset(Account a)
{
    a = new Account();
}

Let's see what happens:

  1. Reset(mine) copies the reference from mine into a.
  2. a = new Account(); puts a reference to a new object into a. Only the copy of the reference changes, and mine still holds the old one.
  3. The method finishes, a disappears, and the new object is left with no reference at all.
  4. mine.Balance prints 100: nobody touched the old account.

The method got its own link and rewrote it to point at another document. Your link did not change.

Here the analogy is inexact. A colleague can keep a forwarded link as long as they like, but a parameter lives only while the method runs. When the method finishes, its copy of the reference disappears. That is why the new account in the example was left with no reference at all.

A parameter with ref

ref passes the variable itself to the method, not a copy of what it holds. This works for a class and for a struct alike—here is a separate program with both cases:

C#
Account acc = new Account();
acc.Balance = 100;
Reset(ref acc);
Console.WriteLine(acc.Balance); // 0

Point pos = new Point();
Shift(ref pos);
Console.WriteLine(pos.X); // 10

void Reset(ref Account a) => a = new Account();
void Shift(ref Point p) => p.X = p.X + 10;

class Account { public int Balance; }
struct Point { public int X; }

ref for an object

With ref, the parameter a is a second name for the variable acc itself. So a = new Account() puts a reference to the new object right into acc, and the program prints 0: the new account has a zero balance.

ref for a struct

Without ref, the method would get a photocopy of the point, as in the previous lesson. With ref, the parameter p is the variable pos itself, and p.X = p.X + 10 moves your point: the program prints 10.

By value or by reference

Interviewers like to ask: are objects passed by reference in C#? The precise answer is no: by default everything is passed by value, and for a class the value is a reference. ref and out from the theme on methods pass by reference.

The table shows what a method can do in each of the four cases:

ParameterWithout refWith ref
structchanges only its own copychanges your struct
classchanges the shared object, but not your variablecan put another object into your variable

Common mistake

A method should swap two accounts, but someone forgot ref:

C#
Account x = new Account();
x.Balance = 1;
Account y = new Account();
y.Balance = 2;
Swap(x, y); // ✗
Console.WriteLine(x.Balance); // 1

void Swap(Account first, Account second)
{
    Account temp = first;
    first = second;
    second = temp;
}

class Account { public int Balance; }

The program compiles and prints 1: the accounts did not swap. Swap got copies of the references and rearranged them inside itself, while x and y still lead to their own objects. This is the trap in the phrase "objects are passed by reference". For the swap to work, you need ref both in the declaration and in the call: Swap(ref x, ref y).

Key points

  • A method with a class parameter gets a copy of the reference and can change the shared object.
  • Assigning a new object to the parameter does not change the caller's variable.
  • ref passes the variable itself: the method can put another object into it or change your struct.
  • By default, C# passes arguments by value, and for a class the value is a reference.