LaVOZs

The World’s Largest Online Community for Developers

'; c# - What's the difference between the 'ref' and 'out' keywords? - LavOzs.Com

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?

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.

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.

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

ref is in and out.

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

out:

In C#, a method can return only one value. If you like to return more than one value, you can use the out keyword. The out modifier return as return-by-reference. The simplest answer is that the keyword “out” is used to get the value from the method.

  1. You don't need to initialize the value in the calling function.
  2. You must assign the value in the called function, otherwise the compiler will report an error.

ref:

In C#, when you pass a value type such as int, float, double etc. as an argument to the method parameter, it is passed by value. Therefore, if you modify the parameter value, it does not affect argument in the method call. But if you mark the parameter with “ref” keyword, it will reflect in the actual variable.

  1. You need to initialize the variable before you call the function.
  2. It’s not mandatory to assign any value to the ref parameter in the method. If you don’t change the value, what is the need to mark it as “ref”?

Extending the Dog, Cat example. The second method with ref changes the object referenced by the caller. Hence "Cat" !!!

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

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

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

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.

ref and out behave similarly except following differences.

  • ref variable must be initialized before use. out variable can be used without assignment
  • out parameter must be treated as an unassigned value by the function that uses it. So, we can use initialized out parameter in the calling code, but the value will be lost when the function executes.

For those that learn by example (like me) here's what Anthony Kolesov is saying.

I've created some minimal examples of ref, out, and others to illustrate the point. I'm not covering best practices, just examples to understand the differences.

https://gist.github.com/2upmedia/6d98a57b68d849ee7091

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

ref means that the value in the ref parameter is already set, the method can read and modify it. Using the ref keyword is the same as saying that the caller is responsible for initializing the value of the parameter.


out tells the compiler that the initialization of object is the responsibility of the function, the function has to assign to the out parameter. It's not allowed to leave it unassigned.

Out: A return statement can be used for returning only one value from a function. However, using output parameters, you can return two values from a function. Output parameters are like reference parameters, except that they transfer data out of the method rather than into it.

The following example illustrates this:

using System;

namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void getValue(out int x )
      {
         int temp = 5;
         x = temp;
      }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;

         Console.WriteLine("Before method call, value of a : {0}", a);

         /* calling a function to get the value */
         n.getValue(out a);

         Console.WriteLine("After method call, value of a : {0}", a);
         Console.ReadLine();

      }
   }
}

ref: A reference parameter is a reference to a memory location of a variable. When you pass parameters by reference, unlike value parameters, a new storage location is not created for these parameters. The reference parameters represent the same memory location as the actual parameters that are supplied to the method.

In C#, you declare the reference parameters using the ref keyword. The following example demonstrates this:

using System;
namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void swap(ref int x, ref int y)
      {
         int temp;

         temp = x; /* save the value of x */
         x = y;   /* put y into x */
         y = temp; /* put temp into y */
       }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;
         int b = 200;

         Console.WriteLine("Before swap, value of a : {0}", a);
         Console.WriteLine("Before swap, value of b : {0}", b);

         /* calling a function to swap the values */
         n.swap(ref a, ref b);

         Console.WriteLine("After swap, value of a : {0}", a);
         Console.WriteLine("After swap, value of b : {0}", b);

         Console.ReadLine();

      }
   }
}

ref and out work just like passing by references and passing by pointers as in C++.

For ref, the argument must declared and initialized.

For out, the argument must declared but may or may not be initialized

        double nbr = 6; // if not initialized we get error
        double dd = doit.square(ref nbr);

        double Half_nbr ; // fine as passed by out, but inside the calling  method you initialize it
        doit.math_routines(nbr, out Half_nbr);

Authoring Time:

(1) We create the calling method Main()

(2) it creates a List object (which is a reference type object) and stores it in the variable myList.

public sealed class Program 
{
    public static Main() 
    {
        List<int> myList = new List<int>();

During Runtime:

(3) Runtime allocates a memory on stack at #00, wide enough to store an address (#00 = myList, since variable names are really just aliases for memory locations)

(4) Runtime creates a list object on heap at memory location #FF( all these addresses are for example sakes)

(5) Runtime would then store the starting address #FF of the object at #00(or in words, stores the reference of the List object in the pointer myList)

Back to Authoring Time:

(6) We then pass the List object as argument myParamList to the called method modifyMyList and assign a new List object to it

List<int> myList = new List<int>();

List<int> newList = ModifyMyList(myList)

public List<int> ModifyMyList(List<int> myParamList){
     myParamList = new List<int>();
     return myParamList;
}

During Runtime:

(7) Runtime starts the call routine for the called method and as part of it, checks the type of parameters.

(8) Upon finding the reference type, it allocates a memory on stack at #04 for aliasing the parameter variable myParamList.

(9) It then stores the value #FF in it as well.

(10) Runtime creates a list object on heap at memory location #004 and replaces #FF in #04 with this value(or dereferenced the original List object and pointed to the new List object in this method)

The address in #00 is not altered and retains the reference to #FF(or the original myList pointer is not disturbed).


The ref keyword is a compiler directive to skip the generation of runtime code for (8) and (9) which means there will be no heap allocation for method parameters. It will use the original #00 pointer to operate on the object at #FF. If the original pointer is not initialised, the runtime will halt complaining it can’t proceed since the variable isn’t initialised

The out keyword is a compiler directive which pretty much is the same as ref with a slight modification at (9) and (10). The compiler expects the argument to be uninitialised and will continue with (8), (4) and (5) to create an object on heap and to stores its starting address in the argument variable. No uninitialised error will be thrown and any previous reference stored will be lost.

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

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.

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.

They're pretty much the same - the only difference is that a variable you pass as an out parameter doesn't need to be initialised, and the method using the ref parameter has to set it to something.

int x;    Foo(out x); // OK 
int y;    Foo(ref y); // Error

Ref parameters are for data that might be modified, out parameters are for data that's an additional output for the function (eg int.TryParse) that are already using the return value for something.

Below I have shown an example using both Ref and out. Now, you all will be cleared about ref and out.

In below mentioned example when i comment //myRefObj = new myClass { Name = "ref outside called!! " }; line, will get an error saying "Use of unassigned local variable 'myRefObj'", but there is no such error in out.

Where to use Ref: when we are calling a procedure with an in parameter and the same parameter will be used to store the output of that proc.

Where to use Out: when we are calling a procedure with no in parameter and teh same param will be used to return the value from that proc. Also note the output

public partial class refAndOutUse : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        myClass myRefObj;
        myRefObj = new myClass { Name = "ref outside called!!  <br/>" };
        myRefFunction(ref myRefObj);
        Response.Write(myRefObj.Name); //ref inside function

        myClass myOutObj;
        myOutFunction(out myOutObj);
        Response.Write(myOutObj.Name); //out inside function
    }

    void myRefFunction(ref myClass refObj)
    {
        refObj.Name = "ref inside function <br/>";
        Response.Write(refObj.Name); //ref inside function
    }
    void myOutFunction(out myClass outObj)
    {
        outObj = new myClass { Name = "out inside function <br/>" }; 
        Response.Write(outObj.Name); //out inside function
    }
}

public class myClass
{
    public string Name { get; set; }
} 
 public static void Main(string[] args)
    {
        //int a=10;
        //change(ref a);
        //Console.WriteLine(a);
        // Console.Read();

        int b;
        change2(out b);
        Console.WriteLine(b);
        Console.Read();
    }
    // static void change(ref int a)
    //{
    //    a = 20;
    //}

     static void change2(out int b)
     {
         b = 20;
     }

you can check this code it will describe you its complete differnce when you use "ref" its mean that u already initialize that int/string

but when you use "out" it works in both conditions wheather u initialize that int/string or not but u must initialize that int/string in that function

Ref: The ref keyword is used to pass an argument as a reference. This means that when value of that parameter is changed in the method, it gets reflected in the calling method. An argument that is passed using a ref keyword must be initialized in the calling method before it is passed to the called method.

Out: The out keyword is also used to pass an argument like ref keyword, but the argument can be passed without assigning any value to it. An argument that is passed using an out keyword must be initialized in the called method before it returns back to calling method.

public class Example
{
 public static void Main() 
 {
 int val1 = 0; //must be initialized 
 int val2; //optional

 Example1(ref val1);
 Console.WriteLine(val1); 

 Example2(out val2);
 Console.WriteLine(val2); 
 }

 static void Example1(ref int value) 
 {
 value = 1;
 }
 static void Example2(out int value) 
 {
 value = 2; 
 }
}

/* Output     1     2     

Ref and out in method overloading

Both ref and out cannot be used in method overloading simultaneously. However, ref and out are treated differently at run-time but they are treated same at compile time (CLR doesn't differentiates between the two while it created IL for ref and out).

From the standpoint of a method which receives a parameter, the difference between ref and out is that C# requires that methods must write to every out parameter before returning, and must not do anything with such a parameter, other than passing it as an out parameter or writing to it, until it has been either passed as an out parameter to another method or written directly. Note that some other languages do not impose such requirements; a virtual or interface method which is declared in C# with an out parameter may be overridden in another language which does not impose any special restrictions on such parameters.

From the standpoint of the caller, C# will in many circumstances assume when calling a method with an out parameter will cause the passed variable to be written without having been read first. This assumption may not be correct when calling methods written in other languages. For example:

struct MyStruct
{
   ...
   myStruct(IDictionary<int, MyStruct> d)
   {
     d.TryGetValue(23, out this);
   }
}

If myDictionary identifies an IDictionary<TKey,TValue> implementation written in a language other than C#, even though MyStruct s = new MyStruct(myDictionary); looks like an assignment, it could potentially leave s unmodified.

Note that constructors written in VB.NET, unlike those in C#, make no assumptions about whether called methods will modify any out parameters, and clear out all fields unconditionally. The odd behavior alluded to above won't occur with code written entirely in VB or entirely in C#, but can occur when code written in C# calls a method written in VB.NET.

If you want to pass your parameter as a ref then you should initialize it before passing parameter to the function else compiler itself will show the error.But in case of out parameter you don't need to initialize the object parameter before passing it to the method.You can initialize the object in the calling method itself.

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

For example,

    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.

I may not be so good at this, but surely strings (even though they are technically reference types and live on the heap) are passed by value, not reference?

        string a = "Hello";

        string b = "goodbye";

        b = a; //attempt to make b point to a, won't work.

        a = "testing";

        Console.WriteLine(b); //this will produce "hello", NOT "testing"!!!!

This why you need ref if you want changes to exist outside of the scope of the function making them, you aren't passing a reference otherwise.

As far as I am aware you only need ref for structs/value types and string itself, as string is a reference type that pretends it is but is not a value type.

I could be completely wrong here though, I am new.

Related
What is the difference between String and string in C#?
What is the difference between const and readonly in C#?
What are the differences between a pointer variable and a reference variable in C++?
Deep cloning objects
Why use the 'ref' keyword when passing an object?
What's the difference between SoftReference and WeakReference in Java?
Difference Between Select and SelectMany
What is the purpose of the var keyword and when should I use it (or omit it)?
When to use in vs ref vs out
Why not inherit from List<T>?