Зачем заполнять С#?
При использовании ключевого слова ref
вызывающий код должен инициализировать переданные аргументы, но с ключевым словом out
нам не нужно этого делать.
- Почему мы не используем
out
везде? - Какая разница между двумя?
- Просьба привести пример ситуации, в которой нам нужно использовать
ref
и не использоватьout
?
Ответы
Ответ 2
out
- это особый вид ref
, где ссылочная память не должна быть инициализирована перед вызовом.
В этом случае компилятор С# обеспечивает соответствие переменной out
перед возвратом метода и что переменная не используется до того, как она была назначена.
Два примера, где out
не работает, но ref
делает:
void NoOp(out int value) // value must be assigned before method returns
{
}
void Increment(out int value) // value cannot be used before it has been assigned
{
value = value + 1;
}
Ответ 3
Ни один из этих ответов не удовлетворил меня, поэтому здесь я принимаю ref
по сравнению с out
.
Мой ответ представляет собой краткое изложение следующих двух страниц:
Сравнение
- И определение метода, и метод вызова должны явно использовать ключевое слово
ref
/out
- Оба ключевых слова вызывают передачу параметров по ссылке (даже типы значений)
- Тем не менее, нет бокса, когда тип значения передается по ссылке
- Свойства не могут передаваться через
out
илиref
, поскольку свойства действительно являются методами -
ref
/out
не считаются частью сигнатуры метода во время компиляции, поэтому методы не могут быть перегружены, если единственная разница между ними заключается в том, что один из методов принимает аргументref
, а другой принимает аргументout
Контраст
ref
- Должен быть инициализирован до его передачи
- Может использовать для передачи значения методу
out
- Не нужно инициализировать до его передачи
- Метод вызова необходим для назначения значения до того, как метод вернет
- Нельзя использовать для передачи значения методу
<сильные > Примеры
Не будет компилироваться, потому что только различие в сигнатурах метода ref
/out
:
public void Add(out int i) { }
public void Add(ref int i) { }
Использование ключевого слова ref
:
public void PrintNames(List<string> names)
{
int index = 0; // initialize first (#1)
foreach(string name in names)
{
IncrementIndex(ref index);
Console.WriteLine(index.ToString() + ". " + name);
}
}
public void IncrementIndex(ref int index)
{
index++; // initial value was passed in (#2)
}
Использование ключевого слова out
:
public void PrintNames(List<string> names)
{
foreach(string name in names)
{
int index; // not initialized (#1)
GetIndex(out index);
Console.WriteLine(index.ToString() + ". " + name);
}
}
public void GetIndex(out int index)
{
index = IndexHelper.GetLatestIndex(); // needs to be assigned a value (#2 & #3)
}
Автор Случайные замечания
- По-моему, концепция использования ключевого слова
out
аналогична использованию значенияOutput
enum ParameterDirection для объявления выходных параметров в ADO.NET - Массивы в С# передаются по ссылке, но для того, чтобы переназначение ссылки на массив повлияло на ссылку в вызывающем коде, необходимо использовать ключевое слово
ref
Пример:
public void ReassignArray(ref int[] array)
{
array = new int[10]; // now the array in the calling code
// will point to this new object
}
Дополнительные сведения о типах ссылок и типах значений см. в Передача параметров ссылочного типа (Руководство по программированию на С#)
Ответ 4
Надуманный пример того, когда вам нужно использовать ref, а не out, выглядит следующим образом:
public void SquareThisNumber(ref int number)
{
number = number * number;
}
int number = 4;
SquareThisNumber(ref number);
Здесь мы хотим, чтобы number
была переменной in-out, поэтому мы используем ref
. Если бы мы использовали out
, компилятор дал бы ошибку, говоря, что мы инициализировали параметр out
перед его использованием.
Ответ 5
Ключевое слово ref позволяет вам изменить значение параметра. Вызываемый метод может быть промежуточным звеном в вызывающей цепочке. Метод, использующий ключевое слово out, может использоваться только в начале вызывающей цепочки.
Другим преимуществом является то, что существующее значение может использоваться в логике метода и по-прежнему удерживать возвращаемое значение.
В функциях Oracle есть явный IN (по умолчанию и то, что вы получаете, если не задаете направление) IN/OUT и OUT. Эквивалент является нормальным (только параметр), ref [parameter] и out [parameter].
Ответ 6
Компилятор знает, что переменные не должны указываться перед вызовом. Это позволяет их просто объявить перед использованием. Однако он знает, что он должен быть установлен перед функцией, которую он использовал в возвратах.
Ответ 7
Когда мы передаем значение при вызове метода с префиксом ключевого слова out
, он рассматривает его совершенно иначе, как мы не передаем его методу. Вместо этого мы фактически собираем (outing) значение переменной out из секции определения метода в параметр переменной метода out, где мы вызываем этот метод.
Итак, out variable
- это результат обработки, выполненной с помощью определения метода, и именно поэтому нам нужно его создать, инициализировать и изменить только в определении.
Используется переменная out
, когда нам нужно возвращать несколько значений из определенного метода.
В то время как в случае переменной ref
нам нужно сначала инициализировать ее, так как ее местоположение памяти передается в определение метода в качестве параметра. Подумайте, что произойдет, если мы не инициализируем его перед прохождением?