简体   繁体   中英

Why ref and out in C#?

While using keyword ref , calling code needs to initialize passed arguments, but with keyword out we need not do so.

  • Why don't we use out everywhere?
  • What is exact difference between the two?
  • Please give example of a situation in which we need to use ref and can't use out ?

The answer is given in this MSDN article . From that post:

The two parameter passing modes addressed by out and ref are subtly different, however they are both very common. The subtle difference between these modes leads to some very common programming errors. These include:

  1. not assigning a value to an out parameter in all control flow paths
  2. not assigning a value to variable which is used as a ref parameter

Because the C# language assigns different definite assignment rules to these different parameter passing modes, these common coding errors are caught by the compiler as being incorrect C# code.

The crux of the decision to include both ref and out parameter passing modes was that allowing the compiler to detect these common coding errors was worth the additional complexity of having both ref and out parameter passing modes in the language.

out is a special form of ref where the referenced memory should not be initialized before the call.

In this case the C# compiler enforces that the out variable is assigned before the method returns and that the variable is not used before it has been assigned.

Two examples where out doesn't work but ref does:

void NoOp(out int value) // value must be assigned before method returns
{
}

void Increment(out int value) // value cannot be used before it has been assigned
{
    value = value + 1;
}

None of these answers satisfied me, so here's my take on ref versus out .

My answer is a summary of the following two pages:

  1. ref (C# Reference)
  2. out (C# Reference)

Compare

  1. Both the method definition and the calling method must explicitly use the ref / out keyword
  2. Both keywords cause parameters to be passed by reference ( even value types )
  3. However, there is no boxing when a value type is passed by reference
  4. Properties cannot be passed via out or ref , because properties are really methods
  5. ref / out are not considered to be part of the method signature at compile time, thus methods cannot be overloaded if the only difference between them is that one of the methods takes a ref argument and the other takes an out argument

Contrast

ref

  1. Must be initialized before it is passed
  2. Can use to pass a value to the method

out

  1. Does not have to be initialized before it is passed
  2. Calling method is required to assign a value before the method returns
  3. Can not use to pass a value to the method

Examples

Won't compile because only difference in method signatures is ref / out :

public void Add(out int i) { }
public void Add(ref int i) { }

Using ref keyword:

public void PrintNames(List<string> names)
{
  int index = 0; // initialize first (#1)

  foreach(string name in names)
  {
    IncrementIndex(ref index);
    Console.WriteLine(index.ToString() + ". " + name);
  }
}

public void IncrementIndex(ref int index)
{
  index++; // initial value was passed in (#2)
}

Using out keyword:

public void PrintNames(List<string> names)
{
  foreach(string name in names)
  {
    int index; // not initialized (#1)

    GetIndex(out index);
    Console.WriteLine(index.ToString() + ". " + name);
  }
}

public void GetIndex(out int index)
{
  index = IndexHelper.GetLatestIndex(); // needs to be assigned a value (#2 & #3)
}

Author's Random Remarks

  1. In my opinion, the concept of using the out keyword is similar to using the Output enum value of ParameterDirection for declaring output parameters in ADO.NET
  2. Arrays in C# are passed by reference, but in order for a reassignment of the array reference to affect the reference in the calling code, the ref keyword must be used

Example:

public void ReassignArray(ref int[] array)
{
  array = new int[10]; // now the array in the calling code
                       // will point to this new object
}

For more info on reference types versus value types, see Passing Reference-Type Parameters (C# Programming Guide)

A contrived example of when you'd need to use ref and not out is as follows:

public void SquareThisNumber(ref int number) 
{
   number = number * number;
}

int number = 4;
SquareThisNumber(ref number);

Here we want number to be an in-out variable, so we use ref . If we had used out , the compiler would have given an error saying we initialized an out param before using it.

The ref keyword allows you to change the value of a parameter. The method being called can be an intermediate link in the calling chain. A method using the out keyword can only be used at the beginning of a calling chain.

Another advantage is that the existing value can be used in the logic of the method and still hold the return value.

In Oracle functions have explicit IN (default and what you get if you don't set a direction) IN/OUT and OUT parameters. The equivalent is normal (just the parameter), ref [parameter], and out [parameter].

The compiler knows that out variables shouldn't set before the call. This allows them be just declared before use. However it knows that it must be set before the function it's used in returns.

When we pass the value while calling the method prefixed by the out keyword, it treats it entirely different like we are not passing it to the method. Instead we are actually collecting (outing) the value of the out variable from the definition section of the method to the method out variable parameter where we are calling that method.

So out variable is the output of processing done with in the method definition, and this is the reason why we need to create it, initialize it, and modify it within the definition only.

An out variable is used when we need return multiple values from a particular method.

While in case of a ref variable we need to initialize it first as its memory location is transfered to method definition as parameter. Think what would happen if we are not initializing it before passing?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM