Little things that you know but forget: Passing a reference type by value

It is a magical world that of legacy code. We can find code that causes astonishment or terror, or any other emotion in between. Sometimes this code has passed through your own hands as well. That’s when all the self-doubting starts: “Did I write that? If not I should certainly have seen it before, why didn’t I fix it?”.

Don’t worry, you’re not alone. This is a common phenomenon; so common, you’d almost call it a certainty. That is where this little series of posts begins: “Little things that you know but forget”. Today, we are looking at the case of passing reference types to methods by value and the little trap that lurks right there.


In our case the code I came across was something like this:

public DataObject BuildDataObject(DataObject obj)
{
obj.Foo = "something";
obj.Bar = 123;
  return obj;
}

Can you spot the problem?

We all know that there are two ways to pass a variable to a method. By value or by reference.

When passing a variable by value we actually pass a copy of the variable to the method being called that is separate to the one in the calling method. So any changes to that copy will not affect the original.

public void foo(int x)
{
x = 200;
}
int number = 100;
foo(number);
Console.Write(number); //prints out 100

When passing a method by reference we pass the actual variable to the method, so any changes made to that variable will persist in the calling context as well.

public void foo(ref int x)
{
x = 200;
}
int number = 100;
foo(ref number);
Console.Write(number); //prints out 200

So far so good, right? Common knowledge, right? It is, until you forget that there is a difference on how concrete values are stored vs reference types.

Concrete types of data (bool, char, int etc.) store their values directly under the memory address where the variable points to. Variables for reference types (i. e. all other objects) store an address to the location in memory for that object.

That means that when you pass a reference type to a method by value, it is the object’s address that gets copied, not the object itself. So this happens:

public void foo(string str)
{
str = "something else";
}
var theString = "this";
foo(theString);
Console.Write(theString); //prints out "something else"

The parameter, even though it is a copy, still is an address pointer to the same object. So we can edit it. The code at the start of this post should be:

public DataObject BuildDataObject(DataObject obj)
{
obj.Foo = "something";
obj.Bar = 123;
}

You might wonder what use there would be in passing a reference type by reference? An example would be swapping the contents of two reference type variables. Have you come by any more? Let me know in the comments below!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.