Использование ключевого слова out в c #

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


person Abbas    schedule 10.10.2011    source источник
comment
См. этот пост с очень похожим вопросом.   -  person Michael Minton    schedule 10.10.2011
comment
Я думаю, что этот пример довольно ясен stackoverflow.com/questions/748062/   -  person xanatos    schedule 10.10.2011


Ответы (8)


Это часто сбивает с толку, и я думаю, что документация MSDN на самом деле немного «ясна, только если она уже известна». То есть это правильно, но на самом деле это имеет смысл только в том случае, если вы уже понимаете концепцию.

Вот как я об этом думаю.

Обычный параметр создает копию значения аргумента. Когда ты говоришь:

static int M(int z) { z = z + 1; return z; }    
...
int x = 123;
int y = M(x);

Это как вы и сказали:

int x = 123;
int z = x; // make a copy of x
z = z + 1;
int y = z;

Параметр ref или out создает псевдоним для существующей переменной. Когда ты говоришь

static void N(ref int q) { q = q + 1; }    
...
int x = 123;
N(x);

Это то же самое, что сказать:

int x = 123;
// MAGIC: q is now an another name for variable x
q = q + 1;

q и x - два разных имени, которые относятся к одной и той же переменной. Увеличение q также увеличивает x, потому что они одинаковы. z и x в предыдущем примере - это два разных имени, которые относятся к двум разным переменным. Увеличение z не меняет x.

Подводя итог: «out» и «ref» просто означают «не создавать новую переменную; скорее, временно сделать второе имя для существующей переменной».

Теперь это ясно?

ОБНОВЛЕНИЕ: Я не сказал, в чем разница между "out" и "ref". Отличие простое. На стороне «вызывающего» «ref» должна быть определенно присвоенной переменной перед вызовом метода. «Выхода» быть не должно. На стороне «вызываемого» «ref» может быть прочитан до того, как он будет записан, но «out» должен быть записан до того, как он будет прочитан. Кроме того, необходимо записать «out», прежде чем элемент управления нормально покинет метод.

person Eric Lippert    schedule 10.10.2011
comment
Не бит, я создал образец проекта, где я создал ниже метод static void N (out int q) {q = q + 1; } теперь он выдает ошибку, говоря об использовании неназначенной локальной переменной q, теперь, как назначить, я уже присвоил значение q. - person Abbas; 10.10.2011
comment
Выходной параметр не обязательно должен быть определенно назначен в вызывающем абоненте перед сайтом вызова. Из-за этого он должен быть назначен перед первым использованием в вызываемой стороне (метод объявления). Вы можете исправить метод в своем комментарии, изменив out на ref. - person phoog; 10.10.2011
comment
@ Аббас: Вы правы; Мне было непонятно, потому что я не сказал, в чем разница между out и ref. Обновление теперь понятно? - person Eric Lippert; 10.10.2011

документация MSDN уже отлично справляется. объясняя это:

Ключевое слово out заставляет аргументы передаваться по ссылке. Это похоже на ключевое слово ref, за исключением того, что ref требует, чтобы переменная была инициализирована перед передачей. Чтобы использовать параметр out, как определение метода, так и вызывающий метод должны явно использовать ключевое слово out. Например:

class OutExample
{
    static void Method(out int i)
    {
        i = 44;
    }
    static void Main()
    {
        int value;
        Method(out value);
        // value is now 44
    }
}
person Icarus    schedule 10.10.2011
comment
Есть еще один важный фактор. Параметр out должен быть определенно назначен перед нормальным возвратом метода. - person phoog; 10.10.2011

Он очень часто используется в шаблоне, который «пытается» получить значение, например:

int result;
if(Int32.TryParse("123", out result))
{
   Console.WriteLine(result + 1);
}
person Mike Christensen    schedule 10.10.2011

Ключевое слово out следует использовать, если вы хотите: а) разрешить вашей функции изменять определенную переменную из вызывающего стека кода И б) принудительно установить значение этой переменной внутри вашей функции.

person Sergey Kudriavtsev    schedule 10.10.2011

MSDN - всегда хорошее место для начала

person Ilia G    schedule 10.10.2011

В большинстве языков, включенных в C #, вы можете передавать значения двумя способами: по значению и по ссылке.

по значению дает методу копию ваших данных, поэтому изменение данных не повлияет на исходные данные

по ссылке по существу дает методу адрес памяти ваших данных, поэтому, если метод изменяет данные, он изменяет оригинал.

Out - это особый тип ссылки, поскольку вам не нужно инициализировать переменную перед вызовом метода, ее можно вызвать с переданным значением null. И она ДОЛЖНА быть установлена ​​методом.

Вы можете думать об этом по-другому (с точки зрения внешнего кода):

val = только чтение

ref = чтение / запись

out = только запись.

person stevenrcfox    schedule 10.10.2011
comment
Параметры Out не только для записи. Было бы очень удобно, если бы они были, я согласен, но это не так, и желание не делает это так. Ограничение на параметры out состоит в том, что в них должна быть записана запись до того, как они будут прочитаны из, а не в том, что они никогда не должны быть прочитаны из. Совершенно законно читать из выходного параметра после того, как он был записан. Именно эта функция делает незаконным обработку выходных параметров контравариантным образом, как это может быть с возвращаемыми типами. - person Eric Lippert; 10.10.2011
comment
@Eric: Надеюсь, вы хотели сказать ковариантную манеру, иначе мне придется перечитать свои книги и ваши серии о ковариации / контравариантности (как будто от таких вещей, как Action ‹Action‹ Action ‹T› ››, у меня не закружилась голова контроля, га). - person Alan; 11.10.2011
comment
@Alan: Ой, вы, конечно, правы. Нормальные по параметрам могут быть контравариантными. Параметры Out могли бы быть ковариантными, если бы они действительно были доступны только для записи, но это не так. - person Eric Lippert; 11.10.2011
comment
@Eric Lippert, я сказал, что это всего лишь возможный способ думать об этом, и я также указываю, что перспектива с точки зрения внешнего кода. Этот последний абзац призван предоставить простую концептуальную модель для предполагаемого использования, а не быть абсолютно точной. - person stevenrcfox; 12.10.2011
comment
@stevenrcfox интересный способ взглянуть на это. Вы также должны добавить ключевое слово для полноты. - person tinker; 07.10.2019

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

Ключевое слово out хорошо, если вы хотите вернуть несколько значений предопределенных типов (например, int, List<string> и DateTime), и вы не хотите создавать новый класс только для этой цели.

person Konrad Morawski    schedule 10.10.2011

Ok,

давайте посмотрим на обычный шаблон для такого рода функций - TrySomething. Предположим, у вас есть функция, которая может успешно дать вам значение или нет, но вы не будете использовать для этого исключение, потому что вам не нужны накладные расходы или это обычная черта. Затем вы обычно возвращаете true, если метод завершился успешно, и false, если нет. Но куда бы вы поместили свое выходное значение?

Один из возможных ответов - использовать такой параметр out:

bool TrySomething(MyInputType input, out MyOutputType output)
{
   output = default(MyOutputType);
   /* ... Try getting the answer ... */
   if (!successful)
      return false;

   output = successfulOutput;
   return true;
}

Примечание. Или вы можете подумать об использовании Tuple<bool,MyOutputType>, и действительно, F # интерпретирует приведенный выше шаблон как приводящий к появлению такого кортежа.

person Random Dev    schedule 10.10.2011