views:

541

answers:

7

In c# , when sending a parameter to a method, when should we use "ref" and when "out" and when without any of them?

+2  A: 

Very simple really. You use exactly the same keyword that the parameter was originally declared with in the method. If it was declared as out, you have to use out. If it was declared as ref, you have to use ref.

Pavel Minaev
I presumed odiseh meant when writing your own methods, but I could be wrong!
RichardOD
exactly, you're right!
odiseh
+11  A: 

In general, you should avoid using ref and out, if possible.

That being said, use ref when the method might need to modify the value. Use out when the method always should assign something to the value.

The difference between ref and out, is that when using out, the compiler enforces the rule, that you need to assign something to the out paramter before returning. When using ref, you must assign a value to the variable before using it as a ref parameter.

Obviously, the above applies, when you are writing your own methods. If you need to call methods that was declared with the ref or out modifiers on their parameters, you should use the same modifier before your parameter, when calling the method.

Also remember, that C# passes reference types (classes) by reference (as in, the reference is passed by value). So if you provide some method with a reference type as a parameter, the method can modify the data of the object; even without ref or out. But it cannot modify the reference itself (as in, it cannot modify which object is being referenced).

driis
My goodness - I spent over 17 minutes typing up my answer - Don't I feel slow today :)
Colin Mackay
To clarify, by default that C# passes the *reference* (to a reference-type instance) **by value**. And the line should read "when the method *might need* to modify the *value*" - simply that the value (in the case of reference-types) is the reference.
Marc Gravell
Small correction about "the only difference" -- you missed one. The other difference is that when using "ref", the compiler enforces the rule that you need to assign something to the ref parameter BEFORE CALLING. That is: int y; M(out y); is legal, but would be illegal if it were ref y.
Eric Lippert
@Marc and Eric, you're both right. I updated the answer.
driis
+9  A: 

They are used mainly to obtain multiple return values from a method call. Personally, I tend to not use them. If I want multiple return values from a method then I'll create a small class to hold them.

ref and out are used when you want something back from the method in that parameter. As I recall, they both actually compile down to the same IL, but C# puts in place some extra stuff so you have to be specific.

Here are some examples:

static void Main(string[] args)
{
    string myString;
    MyMethod0(myString);
    Console.WriteLine(myString);

    Console.ReadLine();
}

public static void MyMethod0(string param1)
{
    param1 = "Hello";
}

The above won't compile because myString is never initialised. If myString is initialised to string.Empty then the output of the program will be a empty line because all MyMethod0 does is assign a new string to a local reference to param1.

static void Main(string[] args)
{
    string myString;
    MyMethod1(out myString);
    Console.WriteLine(myString);

    Console.ReadLine();
}


public static void MyMethod1(out string param1)
{
    param1 = "Hello";
}

myString is not initialised in the Main method, yet, the program outputs "Hello". This is because the myString reference in the Main method is being updated from MyMethod1. MyMethod1 does not expect param1 to already contain anything, so it can be left uninitialised. However, the method should be assigning something.

static void Main(string[] args)
{
    string myString;
    MyMethod2(ref myString);
    Console.WriteLine(myString);

    Console.ReadLine();
}

public static void MyMethod2(ref string param1)
{
    param1 = "Hello";
}

This, again, will not compile. This is because ref demands that myString in the Main method is initialised to something first. But, if the Main method is changed so that myString is initialised to string.Empty then the code will compile and the output will be Hello.

So, the difference is out can be used with an uninitialised object, ref must be passed an initialised object. And if you pass an object without either the reference to it cannot be replaced.

Just to be clear: If the object being passed is a reference type already then the method can update the object and the updates are reflected in the calling code, however the reference to the object cannot be changed. So if I write code like this:

static void Main(string[] args)
{
    string myString = "Hello";
    MyMethod0(myString);
    Console.WriteLine(myString);

    Console.ReadLine();
}

public static void MyMethod0(string param1)
{
    param1 = "World";
}

The output from the program will be Hello, and not World because the method only changed its local copy of the reference, not the reference that was passed in.

I hope this makes sense. My general rule of thumb is simply not to use them. I feel it is a throw back to pre-OO days. (But, that's just my opinion)

Colin Mackay
Great answer!!!
micmoo
Colin, Thank you very much....but suppose that instead of using "param1" as a string (both of us know that string is a reference type)we pass a DataTable to your last method...surprisingly, our DataTable could have some rows in it(ofcourse if the method wants to fill it) and we return to main body of the program, we can do some thing with our DataTable rows. your idea?
odiseh
besides, could you please say some example of what you said first:" Personally, I tend to not use them. If I want multiple return values from a method then I'll create a small class to hold them. "
odiseh
+6  A: 

(this is supplemental to the existing answers - a few extra considerations)

There is another scenario for using ref with C#, more commonly seen in things like XNA... Normally, when you pass a value-type (struct) around, it gets cloned. This uses stack-space and a few CPU cycles, and has the side-effect that any modifications to the struct in the invoked method are lost.

(aside: normally structs should be immutable, but mutable structs isn't uncommon in XNA)

To get around this, it is quite common to see ref in such programs.

But in most programs (i.e. where you are using classes as the default), you can normally just pass the reference "by value" (i.e. no ref/out).


Another very common use-case of out is the Try* pattern, for example:

string s = Console.ReadLine();
int i;
if(int.TryParse(s, out i)) {
    Console.WriteLine("You entered a valid int: " + i);
}

Or similarly, TryGetValue on a dictionary.

This could use a tuple instead, but it is such a common pattern that it is reasonably understood, even by people who struggle with too much ref/out.

Marc Gravell
A: 

Try to avoid using ref. Out is okay, because you know what will happen, the old value will be gone and a new value will be in your variable even if the function failed. However, just by looking at the function you have no idea what will happen to a ref parameter. It may be the same, modified, or an entirely new object.

Whenever I see ref, I get nervous.

MighMoS
A: 

ref is to be avoided (I beleive there is an fx-cop rule for this also) however use ref when the object that is reference may itself changed. If you see the 'ref' keyword you know that the underlying object may no longer be referenced by the same variable after the method is called.

krystan honour
+1  A: 

In addition to Colin's detailed answer, you could also use out parameters to return multiple values from one method call. See for example the method below which returns 3 values.

static void AssignSomeValues(out int first, out bool second, out string third)
    {
        first = 12 + 12;
        second = false;
        third = "Output parameters are okay";
    }

You could use it like so

static void Main(string[] args) {
        int i;
        string s;
        bool b;

        AssignSomeValues(out i, out b, out s);

        Console.WriteLine("Int value: {0}", i);
        Console.WriteLine("Bool value: {0}", b);
        Console.WriteLine("String value: {0}", s);

        //wait for enter key to terminate program
        Console.ReadLine(); }

Just make sure that you assign a valid value to each out parameter to avoid getting an error.

Nick Masao
Thank you......
odiseh