tags:

views:

7569

answers:

12

I'm creating a function where I need to pass an object so that it can be modified by the function. What is the difference between:

public void myFunction(ref MyClass someClass)

and

public void myFunction(out MyClass someClass)

Which should I use and why?

+8  A: 

ref is in and out.

You should use out in preference whereever it suffices for your requirements.

Ruben Bartelink
not quite, as the accepted answer ref if directional and useless ignoring value-types if not passed back out.
kenny
@kenny: Can you clarify a bit please - i.e., which words would you change to maintain the spirit of the answer but remove the inacuracy you percieve? My answer is not a crazy guess from a newbie, but the haste (terseness, typos) in your comment seems to assume it is. The aim is to provide a way of thinking about the difference with the least number of words.
Ruben Bartelink
(BTW I'm familiar with value types, reference types, passing by reference, passing by value, COM and C++ should you find it useful to make reference to those concepts in your clarification)
Ruben Bartelink
@Ruben, I don't disagree, but only a minor nit with 'ref' only for input. I have 2 points. 1 objects are passed by reference always. And the second point is that you only would add a reference if you care what happens in side the method or it has side effects for the caller. I think maybe I misread your answer in the context of the question, I read it as 'ref' is for in and 'out' is for out.
kenny
+48  A: 

Ref tells the compiler that the object is initialized before entering the function, while out tells the compiler that the object will be initialized inside the function.

So while ref is two-ways, out is out-only.

Rune Grimstad
Another cool thing specific to out is that the function has to assign to the out parameter. It's not allowed to leave it unassigned.
Daniel Earwicker
is 'ref' only applicable to value type? Since reference type is always pass by ref.
faulty
Yes. Value types including structs
Rune Grimstad
@faulty: No, ref is not only applicable to value types. ref/out are like pointers in C/C++, they deal with the memory location of the object (indirectly in C#) instead of the direct object.
thr
@faulty: Counterintuitively, Reference types are always passed by value in C#, unless you use the ref specifier. If you set myval=somenewval, the effect is only in that function scope. The ref keyword would allow you to change myval to point to somenewval.
JasonTrue
+3  A: 

Since you're passing in a reference type (a class) there is no need use ref because per default only a reference to the actual object is passed and therefore you always change the object behind the reference.

Example:

public void Foo()
{
    MyClass myObject = new MyClass();
    myObject.Name = "Dog";
    Bar(myObject);
    Console.WriteLine(myObject.Name); // Writes "Cat".
}

public void Bar(MyClass someObject)
{
    someObject.Name = "Cat";
}

As long you pass in a class you don't have to use ref if you want to change the object inside your method.

Albic
This works only if no new object is created and returned. When a new object is created, the reference to the old object would be lost.
etsuba
This is wrong - try the following: add `someObject = null` to `Bar` end execute. Your code will run fine as only `Bar`'s reference to the instance was nulled. Now change `Bar` to `Bar(ref MyClass someObject)` and execute again - you'll get a `NullReferenceException` because `Foo`'s reference to the instance has been nulled too.
Keith
+8  A: 

ref means that value is already set, method can read it and can modify it.

out means that value isn't set and method must set it before return and couldn't read before setting value.

Kaagle
This answer most clearly and concisely explains the restrictions that the compiler imposes when using the out keyword as opposed to the ref keyword.
Dr. Wily's Apprentice
+2  A: 

@Albic. if the ref is superfluous for a reference type, what do you think this code will output?

using System;

namespace DeleteMe
{

    class Class1
    {
     private static void WithRef( ref string s )
     {
      s = "Baker";
     }

     private static void WithoutRef( string s )
     {
      s = "Charlie";
     }

     [STAThread]
     static void Main(string[] args)
     {
      string s = "Able";

      WithRef( ref s );
      WithoutRef( s );

      Console.WriteLine( s );
     }
    }
}
Paul Mitchell
+3  A: 

"Baker"

That's because the first one changes your string-reference to point to "Baker". Changing the reference is possible because you passed it via the ref keyword (=> a reference to a reference to a string). The Second call gets a copy of the reference to the string.

string looks some kind of special at first. But string is just a reference class and if you define

string s = "Able";

then s is a reference to a string class that contains the text "Able"! Another assignment to the same variable via

s = "Baker";

does not change the original string but just creates a new instance and let s point to that instance!

You can try it with the following little code example:

string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);

What do you expect? What you will get is still "Able" because you just set the reference in s to another instance while s2 points to the original instance.

EDIT: string is also immutable which means there is simply no method or property that modifies an existing string instance (you can try to find one in the docs but you won't fins any :-) ). All string manipulation methods return a new string instance! (That's why you often get a better performance when using the StringBuilder class)

rstevens
Exactly. So it's not strictly true to say "Since you're passing in a reference type (a class) there is no need use ref".
Paul Mitchell
In theory it is right to say so because he wrote "so that it can be modified" which isn't possible on strings. But because of immutable objects "ref" and "out" are very useful also for reference types!(.Net contains a lot of immutable classes!)
rstevens
Yes, you're right. I didn't think of immutable objects like strings because most object are mutable.
Albic
A: 

Damn it, I still no gettin' it.. :'(

Cath
+2  A: 

Cath, Let's say Dom shows up at Peter's cubicle about the memo about the TPS reports.

If Dom were a ref argument, he would have a printed copy of the memo.

If Dom were an out argument, he'd make Peter print a new copy of the memo for him to take with him.

jazmatician
+1 for creativity.
A: 

Mind well that the reference parameter which is passed inside the function is directly worked on . eg

    public class MyClass
    {
        public string Name { get; set; }
    }
    public void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog".
    }

    public void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

This will write Dog not Cat hence you should directly work on someObject.

Mangesh Pimpalkar
+1  A: 
BBB
A: 
namespace ConsoleApplication1
{
public class someClass
        {
            public int a;
            public int b;
            public someClass(int c, int d)
            {
                a = c;
                b = d;
            }
        }

    class Program
    {

        public void swapByRef(ref someClass l)
        {
            int c = l.a;
            l.a = l.b;
            l.b = c;
        }

        public void swapNoRef(someClass l)
        {
            int c = l.a;
            l.a = l.b;
            l.b = c;
        }

        static void Main(string[] args)
        {
            Program p = new Program();

            someClass cls= new someClass(2, 3);

            Console.WriteLine("Initial state: {0},{1}", cls.a, cls.b);
            p.swapByRef(ref cls);
            Console.WriteLine("SwapByRef: {0},{1}", cls.a, cls.b);
            p.swapNoRef(cls);
            Console.WriteLine("SwapNoRef: {0},{1}", cls.a, cls.b);

            Console.ReadKey();
        }

why does this output: Initial state: 2,3 SwapByRef: 3,2 SwapNoRef: 2,3

?? Shouldn't only one swap occur? (the one with the ref)

Please help me, I'm migrating from C++ to C# and this issue is very confusing :) Thank you

Nini
No, both must occur. Inside both methods you are changing object properties, not object, so there is no difference.
prostynick
Oh, I see. Thank you very much. But otherwise, if I were to exchange two objects, only the swap with the ref would have worked, right?
Nini
+1  A: 

I am going to try my hand at an explanation:

I think we understand how the value types work right? Value types are (int, long, struct etc.). When you send them in to a function without a ref command it COPIES the data. Anything you do to that data in the function only affects the copy, not the original. The ref command sends the ACTUAL data and any changes will affect the data outside the function.

Ok on to the confusing part, reference types:

Lets create a reference type:

List<string> someobject = new List<string>()

When you new up someobject, two parts are created:

  1. The block of memory that holds data for someobject.
  2. A reference (pointer) to that block of data.

Now when you send in someobject into a method without ref it COPIES the reference pointer, NOT the data. So you now have this:

(outside method) reference1 => someobject
(inside method)  reference2 => someobject

Two references pointing to the same object. If you modify a property on someobject using reference2 it will affect the same data pointed to by reference1.

 (inside method)  reference2.Add("SomeString");
 (outside method) reference1[0] == "SomeString"   //this is true

If you null out reference2 or point it to new data it will not affect reference1 nor the data reference1 points to.

(inside method) reference2 = new List<string>();
(outside method) reference1 != null; reference1[0] == "SomeString" //this is true

The references are now pointing like this:
reference2 => new List<string>()
reference1 => someobject

Now what happens when you send someobject by ref to a method? The actual reference to someobject gets sent to the method. So you now have only one reference to the data:

(outside method) reference1 => someobject;
(inside method)  reference1 => someobject;

But what does this mean? It acts exactly the same as sending someobject not by ref except for two main thing:

1) When you null out the reference inside the method it will null the one outside the method.

 (inside method)  reference1 = null;
 (outside method) reference1 == null;  //true

2) You can now point the reference to a completely different data location and the reference outside the function will now point to the new data location.

 (inside method)  reference1 = new List<string>();
 (outside method) reference1.Count == 0; //this is true
JamesR