6

Possible Duplicates:
Why use ref keyword when passing an Object?
When to pass ref keyword in

What is the correct usage of the 'ref' keyword in C#. I believe there has been plenty of discussion threads on this, but what is not clear to me is:

  1. Is the ref keyword required if you are passing in a reference object? I mean when you create an object in the heap, is it not always passed by reference. Does this have to be explicitly marked as a ref?
Community
  • 1
  • 1
Saibal
  • 802
  • 6
  • 15
  • 1
    Lots of duplicates... [Why use ref keyword when passing an Object?](http://stackoverflow.com/questions/186891/why-use-ref-keyword-when-passing-an-object), [C# ref keyword usage](http://stackoverflow.com/questions/1981916/c-ref-keyword-usage), [When to pass ref keyword in](http://stackoverflow.com/questions/2193064/when-to-pass-ref-keyword-in), [When is using the C# ref keyword ever a good idea?](http://stackoverflow.com/questions/3539252/when-is-using-the-c-ref-keyword-ever-a-good-idea), etc. All of these seem to answer your question. Is there a number 2 that they don't address? – Cody Gray - on strike Jan 27 '11 at 04:05
  • Also a must read is our own Jon Skeet's article on the subject: [Parameter passing in C#](http://www.yoda.arachsys.com/csharp/parameters.html). Unfortunately, I can't vote to close as a duplicate of that. ;-) – Cody Gray - on strike Jan 27 '11 at 04:08

4 Answers4

25

Using ref means that the reference is passed to the function.

The default behaviour is that the function receives a new reference to the same object. This means if you change the value of the reference (e.g. set it to a new object) then you are no longer pointing to the original, source object. When you pass using ref then changing the value of the reference changes the source reference - because they are the same thing.

Consider this:

public class Thing
{
    public string Property {get;set;}
}

public static void Go(Thing thing)
{
    thing = new Thing();
    thing.Property = "Changed";
}

public static void Go(ref Thing thing)
{
    thing = new Thing();
    thing.Property = "Changed";
}

Then if you run

var g = new Thing();

// this will not alter g
Go(g);

// this *will* alter g
Go(ref g);
Kirk Broadhurst
  • 27,836
  • 16
  • 104
  • 169
  • 4
    +1 Finally, a correct answer. It's dangerous to leave questions like this open for very long, because there's too much misinformation floating around out there. It's nice to use something other than a downvote here. – Cody Gray - on strike Jan 27 '11 at 04:17
  • 1
    Scary to think someone downvoted this; I don't want to work with that person! – Kirk Broadhurst Jan 27 '11 at 04:33
  • 1
    Probably people that were upset by the incredible amount of downvotes that have been handed out to answers here. That's the main reason I didn't try to provide my own. Worse is imagining working with the people who still try and argue in the comments. – Cody Gray - on strike Jan 27 '11 at 05:05
16

There is a lot of confusing misinformation in the answers here. The easiest way to understand this is to abandon the idea that "ref" means "by reference". A better way to think about it is that "ref" means "I want this formal parameter on the callee side to be an alias for a particular variable on the caller side".

When you say

void M(ref int y) { y = 123; }
...
int x = 456;
M(ref x);

that is saying "during the call to M, the formal parameter y on the callee side is another name for the variable x on the caller side". Assigning 123 to y is exactly the same as assigning 123 to x because they are the same variable, a variable with two names.

That's all. Don't think about reference types or value types or whatever, don't think about passing by reference or passing by value. All "ref" means is "temporarily make a second name for this variable".

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
0

I believe the ref keyword indicates that you are passing the object by reference, not by value. For example:

void myfunction(ref object a) {
a = new Something();
}

would change the value of a in the calling function However,

void myfunction(object a) {
a = new Something();
}

would change the value of a locally, but not in the calling function. You can still change PROPERTIES of the item, but you cannot set the value of the item itself. For example; a.someproperty = value;

would work in both cases.

bbosak
  • 5,353
  • 7
  • 42
  • 60
  • The second example (without ref) would fail to compile, because it would be like saying 1 = 3. 1 cannot possibly equal 3. However, using ref. It's like saying. x = 1. Then x = 3. – bbosak Jan 27 '11 at 04:07
  • The second example will 'work' but might yield unexpected results! – Kirk Broadhurst Jan 27 '11 at 04:07
  • I guess it COMPILES, but it doesn't change the value of a in the context of the calling function. – bbosak Jan 27 '11 at 04:09
  • It would work in the sense that the reference to `a` is successfully reassigned locally. But that change will not be reflected back to the calling function. It certainly would not cause a compile-time error. – Cody Gray - on strike Jan 27 '11 at 04:09
0
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace InOutRef
{
    static class InOutRef
    {
        public static void In(int i)
        {
            Console.WriteLine(i);
            i=100;
            Console.WriteLine(i);
        }
        public static void Ref(ref int i)
        {
            Console.WriteLine(i);
            i=200;
            Console.WriteLine(i);
        }
        public static void Out(out int i)
        {
            //Console.WriteLine(i); //Error Unsigned Ref
            i=300;
            Console.WriteLine(i);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            int i = 1;
            InOutRef.In(i); //passed by value (in only)
            Debug.Assert(i==1);
            InOutRef.Ref(ref i); //passed by ref (in or out)
            Debug.Assert(i == 200);
            InOutRef.Out(out i); //passed by as out ref (out only)
            Debug.Assert(i == 300);
        }
    }
}

I can't be any more literal on my answer. The code will not remember reference chanages such as the classic Java swap question when using in. However, when using ref, it will be similar to VB.NET as it will remember the changes in and out. If you use the out parameter it means that it must be declared before you return (this is enforced by the compiler).

Output:
1                                  //1 from main 
100                                //100 from in
1                                  //1 is NOT remembered from In
200                                //200 from ref
//should be 200 here but out enforces out param (not printed because commented out)
300                                //300 is out only
Press any key to continue . . .
Community
  • 1
  • 1