How the 'ref' keyword affects the use of objects

This is something that doesn't make any sense until you've stepped through it carefully. And it's something that i didn't understand correctly (or hardly think about) when I was programming in VB.net.

What exact difference does a ref keyword make, when applied to a class-type parameter, anyway?

[VB Note: substitute the keyword ref for ByRef, and know that a C# parameter without a ref keyword is considered ByVal by default. So the sentence above could read: "What exact difference does a ByRef keyword make, when applied to a parameter that is a class-type?"]

First up, a re-cap of how 'ref' affects simpler variable types....

(continues...lots of code examples!)

Imagine we have a little function like this:

    private void TryAndChangeTheValue(string name)

    {

        name = "Ziggy Stardust";           

    }

And we call it with some code like this:

    string Name = "Jimi Hendrix";

    TryAndChangeTheValue(Name);

    MessageBox.Show(Name);

What happens? Does it return 'Jimi Hendrix' or 'Ziggy Stardust'?

It shows 'Jimi Hendrix'. Because the parameter does not have the 'ref' keyword, a copy of the value 'Name' is created, altered and then not returned from the stack. So the initial value of 'Name' is displayed in the messagebox.

If you want the function to affect the displayed message, you need to use the ref keyword, as follows:

    private void TryAndChangeTheValue(ref string name)

    {

        name = "Ziggy Stardust";           

    }

And you need to add the keyword ref to your calling code:

Now when the above code is run, the value 'Ziggy Stardust' will be displayed.

Okay, recap over. Time to think about classes.

But what happens when you do (or don't) use the ref keyword on an object parameter?

Imagine we have a simple little class like this:

    private class NameClass

    {

        public string Value = "Jimi Hendrix";

    }

It has one public field, 'Value' which defaults to 'Jimi Hendrix'.

And now imagine we have a function that looks like this:

    private void TryAndChangeTheValue(NameClass name)

    {

        name.Value = "Ziggy Stardust";           

    }

It accepts a 'NameClass' object, and changes the name property to 'Ziggy Stardust'.

Now what happens when we call the method, and then check the value...

    NameClass name = new NameClass();           

    TryAndChangeTheValue(name);

    MessageBox.Show(name.Value);

Will the messagebox show 'Jimi Hendrix' or 'Ziggy Stardust'?

Before you answer, consider this case:

What if we changed the function to look like this:

    private void TryAndChangeTheValue(ref NameClass name)

    {

        name.Value = "Ziggy Stardust";           

    }

So that now the parameter is of type reference. (We'll also need to add the 'ref' keyword to our calling code)

    NameClass name = new NameClass();           

    TryAndChangeTheValue(ref name);

    MessageBox.Show(name.Value);

Will the 'ref' keyword make any difference to our test? If so, why? If not, why not?

For both these tests, the result will be 'Ziggy Stardust'. The ref keyword won't make a difference to the results.

Does that mean that the ref keyword was ignored? Not at all.

The important thing is that the ref keyword applies to the parameter (name), not to its properties (name.Value).

So let's look at a case where the function doesn't just change a property of the parameters, but tries to change the parameter itself. In that cases the ref parameter will make an important difference.

Here's an example where our function gets sloppy and drops the object.

    private void TryAndChangeTheValue(NameClass name)

    {

        name.Value = "Ziggy Stardust";           

        name = null;           

    }

What will happen now?

Will this code:

    NameClass name = new NameClass();           

    TryAndChangeTheValue(name);

    MessageBox.Show(name.Value);

Still return 'Ziggy Stardust?' Or will we get a null reference exception?

We will still get 'Ziggy Stardust' out. There won't be a null reference exception, because the thing that was set to null was a value copy of the object reference, not a direct reference to the object.

The object itself wasn't affected by the 'name = null' line. That merely stopped a value on the stack from pointing to the object.

And then consider the same code, but with the 'ref' keyword:

    private void TryAndChangeTheValue(ref NameClass name)

    {

        name.Value = "Ziggy Stardust";           

        name = null;           

    }

What will happen when this code is used to call it?

    NameClass name = new NameClass();           

    TryAndChangeTheValue(ref name);

    MessageBox.Show(name.Value);

Will we get a 'ziggy stardust'? Or a null reference exception?

In this case we get a null reference exception. Because now when the name = null line was executed, it was the reference itself that was set to null, not just a copy of it on the stack.

Okay that's all i want to say about that.

Mistakes A-Plenty

Please feel free to point out any mistakes in this article, i'm sure there are plenty. ;-)

(Miss Takesa Plenty sounds like a femme fatale from a James Bond novel... just thought i'd mention it...)


 

I'm currently writing a book about how to build your first product. If you want to build your first product, please sign up to be notified when the book is available.

(By the way, I read every comment and often respond.)

Your comment, please?

Your Name
Your Url (optional)
Note: I may edit, reuse or delete your comment. Don't be mean.