2

我现在不能尝试 rigth,但我敢肯定,有人知道:

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?

如果我想传达当前实施的行为,是否有任何规范?

4

4 回答 4

4

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

C# 语言规范的摘录:

5.1.6 输出参数

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

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

以下明确的分配规则适用于输出参数。请注意 §5.1.5 中描述的参考参数的不同规则。

· 在函数成员或委托调用中将变量作为输出参数传递之前,无需明确分配变量。

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

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

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

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

于 2011-10-05T09:55:26.397 回答
3

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

于 2011-10-05T09:54:03.840 回答
1

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\System\你好.txt

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

你一定会感兴趣的是这个部分

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

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

于 2011-10-05T10:00:23.823 回答
0

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.

于 2011-10-05T10:06:44.970 回答