What's the difference between the 'ref' and 'out' keywords?

Viewed 417008

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?

27 Answers

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.

The ref modifier means that:

  1. The value is already set and
  2. The method can read and modify it.

The out modifier means that:

  1. The Value isn't set and can't be read by the method until it is set.
  2. The method must set it before returning.

ref is in and out.

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

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.

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

For those looking concise answer.

Both ref and out keywords are used to pass-by-reference.


A variable of ref keyword must have a value or must refer to an object or null before its passing.


Unlike ref, a variable of out keyword must have a value or must refer to an object or null after its passing as well as no need to have a value or refer to an object before passing.

As well as allowing you to reassign someone else's variable to a different instance of a class, return multiple values etc, using ref or out lets someone else know what you need from them and what you intend to do with the variable they provide

  • You don't need ref or out if all you're going to do is modify things inside the MyClass instance that is passed in the argument someClass.

    • The calling method will see changes like someClass.Message = "Hello World" whether you use ref, out or nothing
    • Writing someClass = new MyClass() inside myFunction(someClass) swaps out the object seen by the someClass in the scope of the myFunction method only. The calling method still knows about the original MyClass instance it created and passed to your method
  • You need ref or out if you plan on swapping the someClass out for a whole new object and want the calling method to see your change

    • Writing someClass = new MyClass() inside myFunction(out someClass) changes the object seen by the method that called myFunction

Other programmers exist

And they want to know what you're going to do with their data. Imagine you're writing a library that will be used by millions of developers. You want them to know what you're going to do with their variables when they call your methods

  • Using ref makes a statement of "Pass a variable assigned to some value when you call my method. Be aware that I might change it out for something else entirely during the course of my method. Do not expect your variable to be pointing to the old object when I'm done"

  • Using out makes a statement of "Pass a placeholder variable to my method. It doesn't matter whether it has a value or not; the compiler will force me to assign it to a new value. I absolutely guarantee that the object pointed to by your variable before you called my method, will be different by the time I'm done

By the way, in C#7.2 there's an in modifier too

And that prevents the method from swapping out the passed in instance for a different instance. Think of it like saying to those millions of developers "pass me your original variable reference, and I promise not to swap your carefully crafted data out for something else". in has some peculiarities, and in some cases such as where an implicit conversion might be required to make your short compatible with an in int the compiler will temporarily make an int, widen your short to it, pass it by reference and finish up. It can do this because you've declared you're not going to mess with it.


Microsoft did this with the .TryParse methods on the numeric types:

int i = 98234957;
bool success = int.TryParse("123", out i);

By flagging the parameter as out they're actively declaring here "we are definitely going to change your painstakingly crafted value of 98234957 out for something else"

Of course, they kinda have to, for things like parsing value types because if the parse method wasn't allowed to swap out the value type for something else it wouldn't work very well.. But imagine there was some fictitious method in some library you're creating:

public void PoorlyNamedMethod(out SomeClass x)

You can see it's an out, and you can thus know that if you spend hours crunching numbers, creating the perfect SomeClass:

SomeClass x = SpendHoursMakingMeAPerfectSomeClass();
//now give it to the library
PoorlyNamedMethod(out x);

Well that was a waste of time, taking all those hours to make that perfect class. It's definitely going to be tossed away and replaced by PoorlyNamedMethod

To illustrate the many excellent explanations, I developed the following console app:

using System;
using System.Collections.Generic;

namespace CSharpDemos
{
  class Program
  {
    static void Main(string[] args)
    {
      List<string> StringList = new List<string> { "Hello" };
      List<string> StringListRef = new List<string> { "Hallo" };

      AppendWorld(StringList);
      Console.WriteLine(StringList[0] + StringList[1]);

      HalloWelt(ref StringListRef);
      Console.WriteLine(StringListRef[0] + StringListRef[1]);

      CiaoMondo(out List<string> StringListOut);
      Console.WriteLine(StringListOut[0] + StringListOut[1]);
    }

    static void AppendWorld(List<string> LiStri)
    {
      LiStri.Add(" World!");
      LiStri = new List<string> { "¡Hola", " Mundo!" };
      Console.WriteLine(LiStri[0] + LiStri[1]);
    }

    static void HalloWelt(ref List<string> LiStriRef)
     { LiStriRef = new List<string> { LiStriRef[0], " Welt!" }; }

    static void CiaoMondo(out List<string> LiStriOut)
     { LiStriOut = new List<string> { "Ciao", " Mondo!" }; }
   }
}
/*Output:
¡Hola Mundo!
Hello World!
Hallo Welt!
Ciao Mondo!
*/
  • AppendWorld: A copy of StringList named LiStri is passed. At the start of the method, this copy references the original list and therefore can be used to modify this list. Later LiStri references another List<string> object inside the method which doesn't affect the original list.

  • HalloWelt: LiStriRef is an alias of the already initialized ListStringRef. The passed List<string> object is used to initialize a new one, therefore ref was necessary.

  • CiaoMondo: LiStriOut is an alias of ListStringOut and must be initialized.

So, if a method just modifies the object referenced by the passed variable, the compiler will not let you use out and you should not use ref because it would confuse not the compiler but the reader of the code. If the method will make the passed argument reference another object, use ref for an already initialized object and out for methods that must initialize a new object for the passed argument. Besides that, ref and out behave the same.

There 2 main difference that i want to give example for:

  1. ref and out pass by reference, hense;
 class Program
    {
        public static void Main(string[] args)
        {
            var original = new ObjectWithMememberList(3);
            Console.WriteLine(original.MyList.Capacity); // 3
            ChangeList(original.MyList);
            Console.WriteLine(original.MyList.Capacity); // 3
        }

        static void ChangeList(List<int> vr)
        {
            vr = new List<int>(2);
        }
}

but:

 class Program
    {
        public static void Main(string[] args)
        {
            var original = new ObjectWithMememberList(3);
            Console.WriteLine(original.MyList.Capacity); // 3
            ChangeList(ref original.MyList);
            Console.WriteLine(original.MyList.Capacity); // 2
        }

        static void ChangeList(ref List<int> vr)
        {
            vr = new List<int>(2);
        }
}

and same with out. 2. ref argument must be an assignable variable. hense:

ChangeList(ref new List<int>()); // Compile Error [might not be initialized before accessing]

but:

List<int> xs;
ChangeList(out xs); // Compiles
Related