如果使用 out 参数,何时更改调用范围中的变量?

发布于 2024-12-08 02:07:56 字数 351 浏览 0 评论 0原文

我现在无法尝试,但我确信,有人知道:

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

    // do some other stuff here

    // take some time ... and return
}

当我以这样的异步方式调用它时:

MyType a; 
func(out a); 

一旦在函数中分配了 A , a 会立即更改吗?或者仅当函数返回时才将新对象引用分配给 a ?

如果我想继承当前实现的行为,是否有任何规范?

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 asynchronous 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

祁梦 2024-12-15 02:07:56

一旦 A 在函数中被赋值,它就被赋值。 out 的使用提供了对您传入的任何内容的引用,这意味着只要在方法中修改它,它就会被修改。

C# 语言规范摘录:

5.1.6 输出参数

使用 out 修饰符声明的参数是输出参数。

输出参数不会创建新的存储位置。相反,输出参数表示与函数成员或委托调用中作为参数给出的变量相同的存储位置。因此,输出参数的值始终与基础变量相同。

以下明确的赋值规则适用于输出参数。请注意第 5.1.5 节中描述的参考参数的不同规则。

· 变量在可以作为函数成员或委托调用中的输出参数传递之前,无需明确赋值。

· 在函数成员或委托调用正常完成之后,作为输出参数传递的每个变量都被视为在该执行路径中分配。

· 在函数成员或匿名函数中,输出参数最初被视为未分配。

· 函数成员或匿名函数的每个输出参数必须在函数成员或匿名函数正常返回之前明确赋值(第 5.3 节)。

在结构类型的实例构造函数中,this 关键字的行为与结构类型的输出参数完全相同(第 7.6.7 节)。

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

与往事干杯 2024-12-15 02:07:56

一旦线程执行 A = new MyType(); 就会改变它

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

想念有你 2024-12-15 02:07:56

此处也描述了 out,但是一个简短的测试将向您展示什么你需要足够快地知道:

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();
    }
}
}

输出:

我=1

我=5

我=5

编辑:根据您的评论,让我添加以下内容:
正式语言out 关键字的规范文档 不仅限于其他答案之一中所述的第 5.1.6 章,而且还包括第 10.6.1.3 章(第 307 页)如下:

10.6.1.3 输出参数
使用 out 修饰符声明的参数是输出参数。与引用参数类似,输出参数不会创建新的存储位置。相反,输出参数表示与方法调用中作为参数给出的变量相同的存储位置。

当形式参数是输出参数时,方法调用中的相应参数必须由关键字 out 后跟与形式参数类型相同的变量引用(第 5.3.3 节)组成。变量在作为输出参数传递之前不需要明确赋值,但在将变量作为输出参数传递的调用之后,该变量被视为明确赋值。

在方法中,就像局部变量一样,输出参数最初被视为未分配,并且必须在使用其值之前明确分配。

方法的每个输出参数都必须在方法返回之前明确分配。

声明为分部方法 (§10.2.7) 或迭代器 (§10.14) 的方法不能有输出参数。

输出参数通常用在产生多个返回值的方法中。例如:

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);
    }
}

该示例产生输出:

c:\Windows\系统\
你好.txt

请注意,dir 和 name 变量在传递给 SplitPath 之前可以取消分配,并且在调用后它们被视为明确分配。

您一定会对本节感兴趣

与引用参数类似,输出参数不会创建新的存储位置。相反,输出参数表示与方法调用中作为参数给出的变量相同的存储位置。

它清楚地表明该参数没有自己的存储位置,因此在函数中更改它的值将更改原始值。

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.

哭泣的笑容 2024-12-15 02:07:56

这里是一个问题关于引用和线程安全,结论是它不是线程安全的。 out 几乎与 ref 相同(out 也支持空引用),并且它不是线程安全的事实意味着值会立即更改。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文