Когда изменяется переменная из области вызова, если используются параметры out? - PullRequest
2 голосов
/ 05 октября 2011

Я не могу попробовать 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 в функции?Или ссылка на новый объект присваивается только при возврате функции?

Существуют ли какие-либо спецификации, если я хочу передать текущее реализованное поведение?

Ответы [ 4 ]

4 голосов
/ 05 октября 2011

Назначается, если в функции назначено A.Использование out предоставляет ссылку на все, что вы передали, что означает, что оно модифицируется всякий раз, когда оно модифицируется в методе.

Извлечение из спецификации языка C #:

5.1.6 Выходные параметры

Параметр, объявленный с модификатором out, является выходным параметром.

Выходной параметр не создает новое место хранения.Вместо этого выходной параметр представляет то же место хранения, что и переменная, заданная в качестве аргумента в вызове функции-члена или делегата.Таким образом, значение выходного параметра всегда совпадает с базовой переменной.

Следующие определенные правила назначения применяются к выходным параметрам.Обратите внимание на различные правила для ссылочных параметров, описанные в §5.1.5.

· Переменная не обязательно должна быть назначена, прежде чем она может быть передана в качестве выходного параметра в вызове функции-члена или делегата.

· После нормального завершения вызова члена функции или делегата каждая переменная, переданная в качестве выходного параметра, считается назначенной в этом пути выполнения.

· В пределах члена функции или анонимной функции выходной параметризначально считается неназначенным.

· Каждый выходной параметр члена функции или анонимной функции должен быть обязательно назначен (§5.3), прежде чем член функции или анонимная функция вернется нормально.

В конструкторе экземпляраТип структуры, ключевое слово this ведет себя точно как выходной параметр типа структуры (§7.6.7).

3 голосов
/ 05 октября 2011

Это будет изменено, как только поток выполнит A = new MyType ();

1 голос
/ 05 октября 2011

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

вывод:

i = 1

i = 5

i = 5

РЕДАКТИРОВАТЬ: Основываясь на вашем комментарии, позвольте мне добавить следующее: документация спецификации формального языка для ключевого слова out не ограничивается главой 5.1.6, как указано в одном из других ответов, но также рассматривается в главе 10.6.1.3 (стр. 307) следующим образом:

10.6.1.3 Выходные параметры Параметр, объявленный с модификатором out, является выходным параметром.Подобно ссылочному параметру, выходной параметр не создает новое место хранения.Вместо этого выходной параметр представляет то же место хранения, что и переменная, заданная в качестве аргумента в вызове метода.

Когда формальный параметр является выходным параметром, соответствующий аргумент в вызове метода должен состоять из ключевого слова outсопровождаемый ссылкой на переменную (§5.3.3) того же типа, что и формальный параметр.Переменная не обязательно должна быть назначена до того, как она будет передана в качестве выходного параметра, но после вызова, когда переменная была передана в качестве выходного параметра, переменная считается определенно назначенной.

Внутри метода, каклокальная переменная, выходной параметр изначально считается неназначенным и должен быть обязательно назначен перед использованием его значения.

Каждый выходной параметр метода должен быть обязательно назначен до того, как метод вернется.

AМетод, объявленный как частичный метод (§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 \ hello.txt

Обратите внимание, что каталоги переменные name могут быть отменены до того, как они будут переданы в SplitPath, и что они считаются определенно назначенными после вызова.

что вас может заинтересовать, так это раздел

Подобно эталонному параметру, выходной параметр не создает новое место хранения.Вместо этого выходной параметр представляет то же место хранения, что и переменная, заданная в качестве аргумента в вызове метода.

, в которой четко указано, что параметр не имеет собственного места хранения, поэтому изменяя его значениевместо этого в вашей функции будет изменено значение оригинала.

0 голосов
/ 05 октября 2011

Здесь - вопрос о безопасности ссылок и потоков, с выводом, что он не является потокобезопасным.out почти такой же, как ref (out поддерживает также нулевые ссылки), а тот факт, что он не является потокобезопасным, означает, что значения изменяются немедленно.

...