开发者

When is the variable from the calling scope altered, if using out parameters?

开发者 https://www.devze.com 2023-04-11 09:42 出处:网络
I cannot try rigth now, but I am sure, someone knows: void func(out MyType A) { A = new MyType(); // do some other stuff here

I cannot try rigth now, but I am sure, someone knows:

void func(out MyType A) {
    A = new MyType(); 

    // do some other stuff here

    // take some time ... and return
}

When I call this in an asynchron开发者_运维百科ous manner like that:

MyType a; 
func(out a); 

will a be altered immediately, once A is assigned in the function? Or is the new object reference assigned to a only when the function returns?

Are there any specifications if I want to relay on the currently implemented behavior?


It's assigned once A is assigned in the function. The use of out provides a reference to whatever you passed in, which means it gets modified whenever it is modified in the method.

An extract from the C# language spec:

5.1.6 Output parameters

A parameter declared with an out modifier is an output parameter.

An output parameter does not create a new storage location. Instead, an output parameter represents the same storage location as the variable given as the argument in the function member or delegate invocation. Thus, the value of an output parameter is always the same as the underlying variable.

The following definite assignment rules apply to output parameters. Note the different rules for reference parameters described in §5.1.5.

· A variable need not be definitely assigned before it can be passed as an output parameter in a function member or delegate invocation.

· Following the normal completion of a function member or delegate invocation, each variable that was passed as an output parameter is considered assigned in that execution path.

· Within a function member or anonymous function, an output parameter is considered initially unassigned.

· Every output parameter of a function member or anonymous function must be definitely assigned (§5.3) before the function member or anonymous function returns normally.

Within an instance constructor of a struct type, the this keyword behaves exactly as an output parameter of the struct type (§7.6.7).


It will be changed as soon as thread excecute A = new MyType();


out is also described here but a short and simple test will show you what you need to know fast enough:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication1
{
class Program
{
    static void TestOut(out int i)
    {
        i = 5;
        Thread.Sleep(5000);
    }

    static void Main(string[] args)
    {
        int i = 1;
        Console.WriteLine("i = " + i);
        Thread testOut = new Thread(new ThreadStart(() => TestOut(out i)));
        testOut.Start();
        Thread.Sleep(1000);
        Console.WriteLine("i = " + i);
        testOut.Join();
        Console.WriteLine("i = " + i);

        Console.WriteLine("Press ENTER to exit");
        Console.ReadLine();
    }
}
}

output:

i = 1

i = 5

i = 5

EDIT: Based on your comment let me add the following: The formal language specification documentation for the out keyword is not limited to chapter 5.1.6 as stated in one of the other answers but also covered in chapter 10.6.1.3 (p 307) as follows:

10.6.1.3 Output parameters A parameter declared with an out modifier is an output parameter. Similar to a reference parameter, an output parameter does not create a new storage location. Instead, an output parameter represents the same storage location as the variable given as the argument in the method invocation.

When a formal parameter is an output parameter, the corresponding argument in a method invocation must consist of the keyword out followed by a variable-reference (§5.3.3) of the same type as the formal parameter. A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, the variable is considered definitely assigned.

Within a method, just like a local variable, an output parameter is initially considered unassigned and must be definitely assigned before its value is used.

Every output parameter of a method must be definitely assigned before the method returns.

A method declared as a partial method (§10.2.7) or an iterator (§10.14) cannot have output parameters.

Output parameters are typically used in methods that produce multiple return values. For example:

using System;

class Test
{
    static void SplitPath(string path, out string dir, out string name) {
        int i = path.Length;
        while (i > 0) {
            char ch = path[i – 1];
            if (ch == '\\' || ch == '/' || ch == ':') break;
            i--;
        }
        dir = path.Substring(0, i);
        name = path.Substring(i);
    }

    static void Main() {
        string dir, name;
        SplitPath("c:\\Windows\\System\\hello.txt", out dir, out name);
        Console.WriteLine(dir);
        Console.WriteLine(name);
    }
}

The example produces the output:

c:\Windows\System\ hello.txt

Note that the dir and name variables can be unassigned before they are passed to SplitPath, and that they are considered definitely assigned following the call.

what's bound to be of interest to you is this section

Similar to a reference parameter, an output parameter does not create a new storage location. Instead, an output parameter represents the same storage location as the variable given as the argument in the method invocation.

which clearly states the parameter has no storage location of its own, so altering the value of it in your function will alter the value of the original instead.


Here is a question about ref and thread safety, with the conclusion that its not thread safe. out is almost the same as ref (out supports also null references) and the fact that it's not threadsafe means the values are altered immediately.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号