Зачем заполнять С#?

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

  • Почему мы не используем out везде?
  • Какая разница между двумя?
  • Просьба привести пример ситуации, в которой нам нужно использовать ref и не использовать out?

Ответы

Ответ 1

Ответ приведен в статье

Ответ 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 нам нужно сначала инициализировать ее, так как ее местоположение памяти передается в определение метода в качестве параметра. Подумайте, что произойдет, если мы не инициализируем его перед прохождением?