Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Possible Duplicate:
Why are objects passed by reference?

Doesn't C# send the objects themselves? So unless it's some kind of swap function for primitive typed variables - why would I send an object by reference?

share|improve this question
1  
Have you seen this thread: programmers.stackexchange.com/questions/57068/… ? –  Alex In Paris Jul 2 '12 at 7:14
    
Didn't actually find it in my pre-search. But my question is a little different - since C# does work with reference, when would I write myFunc(ref param)? –  JNF Jul 2 '12 at 7:19
2  
This is not a duplicate of that question, except in the sense that neither understand either reference types or ref parameterers. The point of requiring a parameter to be passed by ref, is so that the method can change the value of the VARIABLE/FIELD that was used as an argument. –  jmoreno Jul 6 '12 at 5:30
    
@jnf: in c#, you say 1 of 3 things when you pass a variable as an arguement to a method: you can't change my variable, you MAY change my variable, and you MUST change my variable. Ref/MAY is a compromise between usability, language size, and safety. To achieve the same effect without ref, you'd need to introduce another argument and then to make it as safe, another keyword. Now when would you want to use MAY? When the variable might already contain the value it should. Typically, myFunc will test param, see if it has been initialized/has right value, and if not it will give it the right value. –  jmoreno Jul 6 '12 at 6:27
    
@jnf: note that the above applies whether the argument is an instance of a class, a strucure, or a primitive. Ref means MAY change calling VARIABLE's value. What kind of variable it is and where it is stored are irrelevant, and to an extent just implementation details (there's no fundamental reason why the variable could't be a register for it's entire existence, they just didn't do it that way). –  jmoreno Jul 6 '12 at 6:36
show 1 more comment

marked as duplicate by ChrisF Jul 2 '12 at 19:48

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

6 Answers

up vote 2 down vote accepted

C# doesn't pass the objects themselves. C# passes whatever's in the stack. For value types that are locally-scoped and thus live on the stack, the value is passed down to the next level of the call stack. For all other objects, the data is on the heap and a reference to the heap address is stored on the stack, and is passed around.

In either case, the data that resides on the stack, whether that's the data you care about or a reference "pointer" to the data you care about, is not changed, because when it is passed, it is copied to a new location on the stack and that value is what is manipulated (and then discarded when the method exits and that frame pops off the call stack). If you pass a value type to a method that changes the value, when that method returns to its caller the value will be unchanged, because that copy of the data was never touched by the method. If you pass a reference type, it is the reference that is copied. This means that the data on the heap, pointed to by the reference, can be altered and that will change the data for the caller. BUT, if the passed parameter is reinitialized or otherwise assigned to a different reference, that change will be reverted when the method returns, because that is a change to the reference to the object, which was passed "by value" and doesn't affect the caller's copy of that reference.

For proof, run this test in NUnit:

    [Test]
    public void TestPassObject()
    {
        //instantiate a new instance of some reference type
        var myObj = new object();

        //make a "shallow" copy. This copy will never be touched.
        var myLocalCopy = myObj;

        //Pass the original copy by reference to a method that will alter it.
        var result = TestMethod(myObj);

        //Our original reference value did not change even though
        //the passed reference was reinstantiated.
        //myObj and myLocalCopy are still the same object...
        Assert.AreEqual(myObj, myLocalCopy);
        //and are different from result, even though TestMethod 
        //assigned the reference in result to its passed myObj parameter.
        Assert.AreNotEqual(myObj, result);
    }

    private object TestMethod(object myObj)
    {
        //myObj is a local "copy" of the reference passed by the caller.
        //if you changed myObj's children, the caller would see that,
        //but reinitializing it points the copy to new data on the heap,
        //and does not affect the caller.
        return myObj = new object();
    }

So given that default behavior when not using ref, the answer to your question is that the ref keyword changes what is passed. Instead of passing a copy of the value that resides on the stack, a parameter with the ref keyword is given a "pointer" to the data residing on the stack, whether that's a data value itself or a reference to a data value on the heap. I put "pointer" in quotes because the term is anathema to most .NET coders, but dig down deep enough and that's pretty much what's going on; you're given an immutable pointer to that element of the caller's stack frame.

Behind the scenes, when you use or alter the passed ref parameter, you are using or changing the value of the caller's copy, as pointed to by the ref parameter. This is true regardless of what was passed (data, or a reference to data). This means that you can change a value type's data, or reinitialize/reassign a reference type's reference, and that will affect the caller. However, the syntax remains the same, because the C# spec says it must be so to avoid the confusion that C++ has; in C++, when dealing with a child of your passed parameter, you have to know whether you were given a pointer to an object and must use ., or a pointer to a pointer to an object and must use -> (or a pointer to a pointer to a pointer to an object and must double-dereference, etc etc).

share|improve this answer
add comment

Send objects by reference when you want to have the possibility of modifying the original object. Otherwise, send by value if you just need the value of the object.

Passing by reference happens all the time and isn't just for swap functions.

share|improve this answer
    
Including modifying a single attribute? –  JNF Jul 2 '12 at 7:34
    
Sure, it depends on your model. Usually the object has the functions that operate on its internals but I it's possible that some other object does some sort of accounting and is designed to audit or modify other objects in ways that they normally don't need to do for themselves. –  Alex In Paris Jul 2 '12 at 7:57
    
This seems like a C++ answer. In C# passing by reference happens automatically in most cases. Passing explicitly by reference usually ends up with double indirection - what you would call a double pointer in C++. –  MattDavey Aug 13 '12 at 12:09
add comment

It is necessary to use when you want a method to modify a value type or modify a reference to a reference type, The most commmon reason for doing either of these in code I've seen is interop with C || C++ libraries, e.g. ref int is marshalled to *int.

In pure managed code it tends to be rarer to need ref or out as you mainly use reference types which already give you references to objects rather than copies of objects like value types do. i.e. one level of indirection is all you need most of the time (indeed if you need ref a lot you may be a three star programmer ;)

share|improve this answer
    
out is useful for returning more values from one method, for example in int.TryParse(). –  svick Jul 2 '12 at 12:02
    
yes but out is not ref, and arguably nowadays you might just return a generic tuple or an anonymous type rather than use an out parameter anyway –  jk. Jul 2 '12 at 12:21
    
Tuple certainly is an option, but anonymous type isn't. Return type of a method can't be an anonymous type. –  svick Jul 2 '12 at 13:21
    
yep you are right –  jk. Jul 2 '12 at 13:34
add comment

Making a deep copy of an object is a potentially very expensive operation in terms of both memory and CPU. In some cases (DataTable and friends come to mind), there is even code in place that prevents naive deep copying, although one could question here what is cause and what is effect. If the type of the instance has any sort of global state, making a naive deep copy could potentially be dangerous.

On the other hand, making a deep copy of the value of a primitively-typed variable is quite cheap, and in some cases (for example, immutability of strings) comes essentially for free.

Generally, I feel that functions should not touch their input parameters unless the caller actually wants it to. An easy way to ensure that the caller at least is aware that the callee might alter the input is to require passing by reference, either ref or out as appropriate.

share|improve this answer
add comment

When you pass an object by reference, you can change the value of the reference.

Let's say you have a Person class:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override string ToString()
    {
        return String.Format("Name: {0} - Age: {1}", Name, Age);
    }
}

You also have these functions:

private static void NormalChangeProperties(Person person)
{
    person.Name = "Bob";
    person.Age = 17;
}

private static void NormalAssignNewPerson(Person person)
{
    person = new Person { Age = 55, Name = "John" };
}

private static void NormalSetNull(Person person)
{
    person = null;
}

private static void ByRefChangeProperties(ref Person person)
{
    person.Name = "Bob";
    person.Age = 17;
}

private static void ByRefAssignNewPerson(ref Person person)
{
    person = new Person { Age = 55, Name = "John" };
}

private static void ByRefSetNull(ref Person person)
{
    person = null;
}

And then you have this console app:

static void Main(string[] args)
{
    Person p = new Person { Age = 29, Name = "Kristof" };
    Console.WriteLine("Initial: {0}", p);

    NormalChangeProperties(p);
    Console.WriteLine("After NormalChangeProperties: {0}", p);

    NormalAssignNewPerson(p);
    Console.WriteLine("After NormalAssignNewPerson: {0}", p);

    NormalSetNull(p);
    Console.WriteLine("After NormalSetNull: {0}", p);

    Console.WriteLine("");
    Console.WriteLine("");

    Person p2 = new Person { Age = 29, Name = "Kristof" };
    Console.WriteLine("Initial: {0}", p2);

    ByRefChangeProperties(ref p2);
    Console.WriteLine("After ByRefChangeProperties: {0}", p2);

    ByRefAssignNewPerson(ref p2);
    Console.WriteLine("After ByRefAssignNewPerson: {0}", p2);

    ByRefSetNull(ref p2);
    Console.WriteLine("After ByRefSetNull: {0}", p2 != null ? p2.ToString() : "null");

    Console.ReadLine();
}

The output will be:

Initial: Name: Kristof - Age: 29
After NormalChangeProperties: Name: Bob - Age: 17
After NormalAssignNewPerson: Name: Bob - Age: 17
After NormallSetNull: Name: Bob - Age: 17


Initial: Name: Kristof - Age: 29
After ByRefChangeProperties: Name: Bob - Age: 17
After ByRefAssignNewPerson: Name: John - Age: 55
After ByRefSetNull: null

As you can see, assigning a new value (as opposed to changing properties) or setting it to null (which is also changing the value) of the reference itself, requires you pass by reference.

For a better and more detailed explanation, you can have a look at this article by Jon Skeet.

share|improve this answer
7  
This only explains what it does, not why you would want to. –  DeadMG Jul 2 '12 at 9:44
6  
Well obviously you would want to when you require any of the behaviour it provides :-) To quote Jon Skeet: " you almost never need to use ref/out. It's basically a way of getting another return value, and should usually be avoided precisely because it means the method's probably trying to do too much. That's not always the case (TryParse etc are the canonical examples of reasonable use of out) but using ref/out should be a relative rarity." –  Kristof Claes Jul 2 '12 at 10:35
    
out is a little different and arguably a little cleaner than ref though. I suspect if int.TryParse et al were written now they would probably return a tuple (int,bool) so essentially interop with legacy code and native dlls is probably you primary motivation –  jk. Jul 2 '12 at 10:42
    
I'm not so sure about that, jk. Being able to stick a TryParse into a conditional while simultaneously having its output end up somewhere feels a bit cleaner. Also, Boolean.TryParse returning a Tuple would make me very sad, as Tuples don't name their parameters. –  Brian Jul 2 '12 at 13:55
add comment

C# sends references to objects all the time. That is, when you do

void Bar (myObject obj)
{
    obj.Name = "Hi";
    obj = new myObject();
}

obj is a value that contains a reference to an instance of myObject allocated on the heap. If we get behind the metaphor of passing entire objects in any sort of way, it's really not at all different from an integer. The reference itself is passed by value (by being copied byte by byte), but the thing the reference points to obviously stays the same.

When you use the ref keyword, what you pass is a reference to a variable (note the emphasis; compare with the above). ref int would be a reference to an integer variable. Again, the reference is copied byte by byte (a process that is completely opaque to you), but the thing the reference points to stays the same.

So, just like obj is a reference to an instance of myObject, ref myObject obj2 would be a reference to a variable containing a reference to an instance of an object, or in other words, a reference to a reference of myObject.

The out keyword does the same thing, except that the reference is assumed to point to null.

Okay, now that we've gotten past that, let's contend with the question of why the hell do this.

Well, the short answer is, do not use the ref keyword. The slightly longer answer is, Do not use the ref keyword unless you really can't avoid it.. Especially do not use it with anything except local variables (e.g. do not use it with fields and the like), and really really don't use it on reference types.

There are several reasons for this rationale. First of all, keeping the number of function returns at a minimum helps comprehension. It reduces the number of diverging pathways your code can possibly take.

Then, passing things by reference opens up a whole slew of nasty typing and mutability problems. Let's say I have an instance MyChild : MyParent, and there is a method that takes MyParent by reference. When I pass MyChild to the method, I can never know if I'm getting an object of type MyChild back. In broader terms, you really have no idea what sort of object you'll be getting back when you send something in by ref. It could be the same instance, it could be another instance, it could be another type altogether.

share|improve this answer
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.