Насколько я могу сказать, единственное использование для out
параметры - то, что вызывающая сторона может получить несколько возвращаемых значений из вызова отдельного метода. Но мы можем также получить несколько использований значений результата ref
параметры вместо этого!
Так есть ли другие ситуации где out
параметры могли оказаться полезными и где мы не могли использовать ref
параметры вместо этого?
Спасибо.
Да - разница между ref
и out
заключается в определенном назначении:
Параметр out
не должен быть определенно назначен вызывающей стороной перед вызовом метода. Он действительно должен быть определенно назначен в методе, прежде чем он вернется нормально (то есть без исключения).Затем переменная определенно назначается в вызывающем после вызова.
Параметр 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
соответственно. Таким образом становится ясно, что входит в метод ( текст
) и что выходит (две части информации: ok
и значение
).
Это было бы просто недоступно, если бы int.TryParse
использовал вместо этого параметр ref
- поскольку компилятор не может знать, будет ли он на самом деле заботиться о начальном значении параметра ref
.
Одно из важных различий заключается в следующем:
Переменная, переданная в качестве аргумента out. не обязательно должна быть инициализирована. Однако параметру out должно быть присвоено значение до возвращения метода.
(Для параметра ref это не требуется)
Источник: http://msdn.microsoft.com/en-us/library/t3c3bfhx(VS.71).aspx
Вы можете рассматривать параметры таким образом:
обычные параметры - это in параметры:
Значение может войти в функцию через такой параметр; поэтому он должен быть инициализирован.
ref
параметры - это in-out параметры:
Через такой параметр значение может войти в функцию и выйти из нее. Из-за первого он также должен быть инициализирован.
out
параметры - out параметры:
Значение должно возвращаться из функции только через такой параметр; поэтому его не нужно инициализировать.
Я пришел к такому взгляду на ref
/out
параметры, изучая технологию COM компании Microsoft. IDL (язык описания интерфейсов) используется для описания интерфейсов компонентов COM, а в IDL параметры дополняются деклараторами in
, out
и inout
. Я подозреваю, что .NET и C# частично унаследовали эти деклараторы от COM, хотя и с немного другими именами (ref
вместо inout
).
В COM параметры out
часто используются для получения фактического возвращаемого значения метода интерфейса, поскольку "реальное" возвращаемое значение часто уже используется для возврата кода успеха/ошибки HRESULT
.
В .NET, я думаю, out
параметры имеют гораздо меньшее значение, даже в тех случаях, когда вы хотите вернуть несколько значений из метода (в таких ситуациях вы можете возвращать сложные объекты или Tuple
).
Параметр out
полезен, когда вы хотите получить несколько значений результата из метода. Технически вы можете использовать параметр ref
для достижения той же цели, но параметр out
значительно лучше передает намерение. Когда вы используете ref
, непонятно, почему вы делаете это вместо использования out
или вместо использования результата функции. Предположительно, вы намереваетесь изменить переданное значение, но почему вы меняете его, неясно просто из сигнатуры функции.
Я думаю, что прекрасный пример - int.TryParse ()
http://msdn.microsoft.com/en-us/library/f02979c7.aspx
Основная причина того, что out лучше, чем ref , состоит в том, что вам не нужно назначать фиктивное значение возвращаемой переменной перед вызовом (даже неявно).
Итак, out сообщает вам и компилятору: «Эта переменная будет назначена в методе. И начальное значение переменной, если оно есть, даже не будет рассматриваться».
Основное различие между ними заключается в том, что если мы используем ref , то мы должны инициализировать его перед вызовом, и необязательно, чтобы мы присвоили значение нашей переменной ref в нашем метод.
Однако для методов out нам не нужно явно инициализировать их, но в нашем методе мы должны присвоить ему какое-то значение, иначе они будут генерировать ошибку времени компиляции.