简体   繁体   中英

C# Passing reference type directly vs out parameter

I have two methods:

public void A(List<int> nums) 
{
    nums.Add(10);
}

public void B(out List<int> nums)
{
    nums.Add(10);
}

What is the difference between these two calls?

List<int> numsA = new List<int>();
A(numsA);

List<int> numsB = new List<int>();
B(out numsB); 

In general, I am trying to understand the difference between passing reference types as-is or as out parameters.

In your example, method B will fail to compile, because an out parameter is considered to be uninitialized, so you have to initialize it before you can use it. Also, when calling a method with an out parameter, you need to specify the out keyword at the call site:

B(out numsB);

And you don't need to initialize the numbsB variable before the call, because it will be overwritten by the method.

Jon Skeet has a great article that explains the various ways to pass parameters: Parameter passing in C#

A non-ref, non-out parameter, like a local variable, denotes a storage location. If the storage location's type is a reference type, then the storage location holds a reference to an instance of that type.

Ref and out parameters, by contrast, hold a reference to a storage location. That storage location could be a local variable, a field, or an array element. In other words, ref and out parameters introduce another layer of indirection. If you have a reference-type ref or out parameter in a method, it therefore represents a reference to a reference to an object.

Why would you want a reference to a reference to an object? In case you need to modify the reference to the object (as opposed to modifying the object itself).

This is a useful technique in some narrow circumstances. For example, you might want to write a function that orders two queues depending on which has the smaller value on top:

void OrderQueues(ref Queue<int> a, ref Queue<int> b)
{
    if (a.Peek <= b.Peek) return;
    var temp = a;
    a = b;
    b = temp;
}

Out parameters are useful if you want to return more than one value from a method:

void OldestAndYoungest(IEnumerable<Person> people, out Person youngest, out Person oldest)
{
    youngest = null;
    oldest = null;
    foreach (var person in people)
    {
        if (youngest == null || person.Age < youngest.Age)
            youngest = person;
        if (oldest == null || oldest.Age < person.Age)
            oldest = person;
    }
}

In my experience, ref and out parameters are fairly rare, and even rarer with reference types.

Note that a ref parameter must be initialized by the caller, while an out parameter must be initialized by the callee. If you never assign a value to the ref parameter, then it should probably be a "normal" parameter. If you never assign a value to an out parameter, as in your example, your code will not compile.

The out keyword causes arguments to be passed by reference. This is similar to the ref keyword, except that ref requires that the variable be initialized before being passed. To use an out parameter, both the method definition and the calling method must explicitly use the out keyword. For example:

http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx

In version B, the function has direct access to the variable. It's like the 'ref' keyword, except that the variable must be assigned from within the function taking the parameter. It lets you return multiple values from a function. And the call syntax is 'B(out numsB);'

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