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?

  • 1
    Have you seen this thread: programmers.stackexchange.com/questions/57068/… ? 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

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:

    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).


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);

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

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

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


    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");


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.

  • 8
    This only explains what it does, not why you would want to.
    – DeadMG
    Jul 2 '12 at 9:44
  • 7
    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." 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
  • 1
    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
  • With the new conditional-dot in C# 5, maybe we need to rethink TryParse. Aug 27 '15 at 17:42

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 ;)

  • 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

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.


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.

  • 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. 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

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