Click here to Skip to main content
Click here to Skip to main content

Ref Keyword for Reference Types

By , 15 Sep 2009
 

The Ref keyword is well known. It indicates that you are passing a reference, not a value, to a method. That means that if the method modifies the value, the changes will be apparent to the calling method as well.

Where I see a lot of confusion, however, is what happens when dealing with reference types. It is common to say that methods pass objects by reference, but that's not entirely true.

First, a pop quiz. Without actually running the code, what do you think this code snippet will produce?

using System;

namespace ByRef
{
    internal sealed class MyClass
    {
        public MyClass(int value)
        {
            Value = value;
        }

        public int Value { get; set; }
    }

    internal class Program
    {
        private static void _SwapByValue(MyClass myClass)
        {
            myClass = new MyClass(5);
        }
   
        private static void _SwapByRef(ref MyClass myClass)
        {
            myClass = new MyClass(5);
        }
        
        private static void Main(string[] args)
        {
            MyClass testclass = new MyClass(4);
            _SwapByValue(testclass);
            Console.WriteLine(testclass.Value);
           
            MyClass testclass2 = new MyClass(4);
            _SwapByRef(ref testclass2);
            Console.WriteLine(testclass2.Value);            

            Console.ReadLine();
        }
    }
}

We'll come back to that in a minute.

When you make a method call, all of the variables you pass are copied to the stack. This is the first place some people get confused. If I have an integer:

int x = 5;
CallMethod(x);

x is on my stack. A copy of the value of x ("5") is made and also placed on the stack. We now have two stack entries: "my x" and "the method's x."

But what about this?

MyClass myClass = new MyClass(5);
CallMethod(myClass);

The important thing to remember is that myClass is really a reference to the instance. So the first line gives us two allocations in memory: a block of heap that contains the class, and a local stack pointer to the class. So when we call the method, a copy is made just as in the value type example. In this case, it is a copy of the reference. So now I have my class in the heap, my local reference, and a copy of my local reference being passed to the method.

This is why the first case in the above example will print "4". All the method did was to change the reference on the method's stack to point to a new allocation in the heap - the new instance of MyClass. When the method returns, the copy is forgotten. The new instance (5) becomes orphaned, and is eventually garbage collected. The local reference still points to (4).

The second case is more interesting. As we mentioned, the ref keyword forces a reference, not a copy, to be passed. So this:

int x = 5;
MyMethod(ref x);

Skips making the copy. It simply gives the method access to the "5" value on the stack (some people mistakenly believe that the 5 is somehow boxed or unboxed, but that doesn't happen ... it simply isn't copied). If you change it, you change the same stack reference the calling program has, and therefore it will recognize the change.

What about with our object? This is where understanding the ref keyword is, well, key. Remember that when we new the (4) class, we have two important pieces: the class on the heap, and the pointer to the class (reference) on the stack. When we call the method with the ref keyword, it is not allowed to make a copy. Therefore, the method gains access to the same reference on the stack as the calling program. When it makes a new class (5), the stack reference is changed to point to this new instance. Now, the references point to (5) and (4) is orphaned and will be subject to garbage collection. This is why the second example shows "5" — the reference has been updated.

So, as you can see, objects are not "passed by reference" by default. Instead, when an reference type is passed in a parameter list, the reference is passed by value. This allows you to modify the object. If you want to change the reference, then you must ref it!

Jeremy Likness

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Jeremy Likness
Architect Wintellect
United States United States
Member
Jeremy Likness is a Microsoft Silverlight MVP who works as Project Manager and Senior Consultant for Wintellect with 15 years of experience developing enterprise applications. He has worked with software in multiple verticals ranging from insurance, health and wellness, supply chain management, and mobility. His primary focus for the past decade has been building highly scalable web-based solutions using the Microsoft technology stack with a focus on Silverlight since version 2.0.
 
Prior to Wintellect, Jeremy was Director of Information Technology and served as development manager and architect for AirWatch, LLC, where he helped the company grow and solidify its position as one of the leading wireless technology solution providers in the United States by managing the development of their product portfolio that includes public HotSpot solutions and a management console for enterprise grade wireless networks, mobile devices, and their consumers. A fluent Spanish speaker, Jeremy served as Director of Information Technology for Hispanicare, where he architected a multi-lingual content management system for the company's Hispanic-focused online diet program. Jeremy accepted his role there after serving as Development Manager for Manhattan Associates, a software company that provides supply chain management solutions.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralSimilar article PinmemberDarchangel21 Sep '09 - 6:28 
GeneralSort of... PinmemberMartin Kalitis21 Sep '09 - 4:54 
I guess you are mostly there. In the first part of your example code you are attempting to replace the passed in reference with a new reference which will not work. However if you were to change the value of the MyClass object then this would be reflected upon return from the function. This is because you are working on the _reference_ to the instance of MyClass.
 
The second function call (SwapByRef) means that you want to replace the referring reference with a new instance reference (It's similar to a instance** pointer in C/C++). This is difficult to explain without a whiteboard and a PowerPoint presentation perhapsSmile | :)
 
When you mention boxing/unboxing this would be true if it was a value type - the whole boxing/unboxing means the translation between a 'value type-to-a reference-to-a value type'. In essence, changing MyClass from a class to a struct is an example of boxing/unboxing since a struct in c# is a value type.
 
Hope this makes sense, if not then please let me know and I'll have another crack of explaining this. A good effort in seeing this issue though, many others I'm sure have seen 'strange' things happening in their code and have not understood why they are happening.
 
Ciao,
 
M.
GeneralRe: Sort of... PinmemberJeremy Likness21 Sep '09 - 5:02 
GeneralRe: Sort of... [modified] PinmemberMartin Kalitis21 Sep '09 - 5:09 
GeneralRe: Sort of... PinmemberJeremy Likness21 Sep '09 - 5:16 
GeneralRe: Sort of... PinmemberMartin Kalitis21 Sep '09 - 5:56 
GeneralRe: Sort of... PinmemberJeremy Likness23 Sep '09 - 0:06 
GeneralRe: Sort of... PinmemberMartin Kalitis21 Sep '09 - 5:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 16 Sep 2009
Article Copyright 2009 by Jeremy Likness
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid