В каких ситуациях полезны параметры out (где вместо него нельзя использовать ref)? - PullRequest
18 голосов
/ 27 июня 2010

Насколько я могу судить, единственное использование параметров out заключается в том, что вызывающая сторона может получить несколько возвращаемых значений из одного вызова метода.Но мы также можем получить несколько значений результата, используя вместо этого ref параметры!

Так есть ли другие ситуации, когда out параметры могут оказаться полезными и где мы не можем использовать ref параметры вместо этого?

Спасибо.

Ответы [ 6 ]

29 голосов
/ 27 июня 2010

Да - разница между ref и out в терминах определенного назначения:

  • Параметр out не обязательно должен быть назначен вызывающей стороной перед вызовом метода. Он действительно должен быть определенно назначен в методе, прежде чем он вернется нормально (т.е. без исключения). Затем переменная определенно присваивается вызывающей стороне после вызова.

  • A ref параметр действительно должен быть определенно назначен вызывающей стороной перед вызовом метода. не нужно назначать другое значение в методе.

Предположим, мы хотели изменить int.TryParse(string, out int) на ref. Обычно вызывающий код выглядит так:

int value;
if (int.TryParse(text, out value))
{
    // Use value
}
else
{
    // Do something else
}

Теперь, если бы мы использовали ref, нам нужно было бы дать value значение перед вызовом, например ::

int value = 0;
if (int.TryParse(text, ref value))
{
    // Use value
}
else
{
    // Do something else
}

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

Одна из рекомендаций, которые я сделал для C # 5 (я понятия не имею, будет ли он задействован или нет), заключается в том, что метод с параметром out должен рассматриваться как метод, возвращающий кортеж значений. В сочетании с улучшенной поддержкой кортежей это может означать, что мы можем сделать что-то вроде этого:

var (ok, value) = int.TryParse(text);

В этом случае ok и value будут неявно введены в bool и int соответственно. Таким образом, становится ясно, что входит в метод (text) и что выходит (две части информации: ok и value).

Это просто было бы недоступно, если бы int.TryParse использовал вместо этого параметр ref - так как компилятор не может знать, собирается ли он на самом деле заботиться о начальном значении параметра ref .

8 голосов
/ 27 июня 2010

Параметры можно посмотреть следующим образом:

  • нормальные параметры in параметры: Значение может входить в функцию через такой параметр;следовательно, он должен быть инициализирован.

  • ref параметры вход параметры: Значение может входить и выходить из функции через такой параметр.Из-за первого он также должен быть инициализирован.

  • out параметры out параметры: Предполагается, что значение может возвращаться из функции только через такой параметр;следовательно, его не нужно инициализировать.

Я пришел к такому взгляду на параметры ref / out, изучив технологию Microsoft COM.IDL (язык описания интерфейса) используется для описания интерфейсов COM-компонентов, а с IDL параметры дополняются с помощью объявлений in, out и inout.Я подозреваю, что .NET и C # частично унаследовали эти деклараторы от COM, хотя и с немного другими именами (ref вместо inout).

С COM, параметры out часто используются для получения интерфейсафактическое возвращаемое значение метода, поскольку «реальное» возвращаемое значение часто уже используется для возврата HRESULT кода успеха / ошибки.

С .NET я думаю, что out параметры имеют гораздо меньшее значение, даже вслучаи, когда вы хотите вернуть несколько значений из метода (вы можете вернуть сложные объекты или Tuple s в этих ситуациях).

4 голосов
/ 27 июня 2010

Одно важное отличие заключается в следующем:

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

(параметр ref не требует этого)

Источник: http://msdn.microsoft.com/en-us/library/t3c3bfhx(VS.71).aspx

2 голосов
/ 27 июня 2010

Я думаю, что хорошим примером является int.TryParse ()

http://msdn.microsoft.com/en-us/library/f02979c7.aspx

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

Итак, out сообщает вам и компилятору: «Этот var будет назначен в методе. И начальное значение var, если оно есть, даже не будет просматриваться».

2 голосов
/ 27 июня 2010

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

0 голосов
/ 28 июня 2010

Основное различие между ними состоит в том, что если мы используем ref , то мы должны инициализировать это перед вызовом, и необязательно, чтобы мы присваивали значение нашей переменной ref вmethod.

Однако для out методов нам не нужно явно инициализировать их, но в нашем методе мы должны присвоить ему какое-то значение, иначе они вызовут ошибку времени компиляции.

...