Что такое out в c
Перейти к содержимому

Что такое out в c

параметр out

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

Чем out отличается от ref?

Разница в том, что out — это выходной параметр, а ref — входно-выходной.

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

(Таким образом, ref -параметр немного напоминает инициализированную локальную переменную, а out -параметр — неинициализированную.)

private void func1(out string value) < Console.WriteLine(value); // нельзя, value не инициализировано if (false) return; // нельзя, забыли установить значение value value = "Hello World!"; >string s1; func1(out s1); 
private void func2(ref string value) < Console.WriteLine(value); // можно if (false) return; // не проблема, у value остаётся старое значение value = "Hello World!"; >string s2; func2(ref s2); // нельзя, функция имеет право использовать значение, // значит, оно должно быть инициализировано сначала 

Таким образом, out -параметр — это как бы дополнительное возвращаемое значение функции. А ref -параметр — просто параметр, изменения которого видны снаружи функции.

На уровне CLR для out — и ref -параметров используется один и тот же механизм, но это незначительная техническая подробность. Разница в семантике.

Основы C# — ключевые слова Ref и Out

Когда мы передаем аргумент типа int, double, decimal и т.д. (базовые типы значений), мы передаем не фактическое значение, а его копию. Это означает, что наши исходные значения не меняются внутри методов, потому что мы передаем новую копию исходного значения. В результате все операции внутри метода выполняются с копируемым значением.

Мы можем показать это на примере:

class Program < public static void ChangeAndWrite(int number) < number = 10; Console.WriteLine($"Inside ChangeAndWrite method, number value is: "); > static void Main(string[] args) < int number = 5; Console.WriteLine($"Value of the number prior to ChangeAndWrite call is: "); ChangeAndWrite(number); Console.WriteLine($"Value of the number after the ChangeAndWrite call is: "); Console.ReadKey(); > > 

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

Использование ключевых слов Ref и Out

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

Мы можем использовать ключевое слово ref , только если переменная, которую мы используем в качестве аргумента, инициализирована перед вызовом метода. Используя ключевое слово out , нам не нужно инициализировать переменную перед вызовом метода, но мы должны инициализировать ее внутри метода.

Итак, давайте упростим. Если мы хотим изменить существующее значение переменной внутри метода, мы будем использовать ключевое слово ref . Но если мы хотим присвоить совершенно новое значение переменной внутри метода, мы используем ключевое слово out .

Пример для типа значения

В предыдущем примере мы видели, как ведут себя переменные типа значения, если мы не используем ключевые слова ref или out. В этом примере мы увидим поведение переменных типа значения при использовании этих ключевых слов:

class Program < public static void ChangeRef(ref int numberRef) < numberRef = 25; Console.WriteLine($"Inside the ChangeRef method the numberRef is "); > public static void ChangeOut( out int numberOut) < numberOut = 60; Console.WriteLine($"Inside the ChangeOut method the numberOut is "); > static void Main(string[] args) < int numberRef = 15; Console.WriteLine($"Before calling the ChangeRef method the numberRef is "); ChangeRef(ref numberRef); Console.WriteLine($"After calling the ChangeRef method the numberRef is "); Console.WriteLine(); int numberOut; Console.WriteLine("Before calling the ChangeOut method the numberOut is unassigned"); ChangeOut(out numberOut); Console.WriteLine($"After calling the ChangeOut method the numberOut is "); Console.ReadKey(); > > 

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

Пример для ссылочного типа

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

Тем не менее, мы можем использовать ключевое слово ref со ссылочными типами, если мы хотим создать новый объект с тем же адресом.

Давайте посмотрим это на примере:

class Program < public static void ChangeColor(Pen pen) < pen.Color = Color.Green; Console.WriteLine($"Inside the ChangeColor method the color is "); > public static void CreateNewObjectWithoutRef(Pen pen) < pen = new Pen(Color.Red); Console.WriteLine($"Inside the CreateNewObjectWithoutRef method the color of new pen object is "); > public static void CreateNewObjectWithRef(ref Pen pen) < pen = new Pen(Color.Yellow); Console.WriteLine($"Inside the CreateNewObjectWithRef method the color of new pen object is "); > static void Main(string[] args) < Pen pen = new Pen(Color.Blue); Console.WriteLine($"Before ChangeColor method: "); ChangeColor(pen); Console.WriteLine($"After the ChangeColor method: "); Console.WriteLine(); Console.WriteLine($"Before CreateNewObjectWithoutRef method: "); CreateNewObjectWithoutRef(pen); Console.WriteLine($"After CreateNewObjectWithoutRef method: "); Console.WriteLine(); Console.WriteLine($"Before CreateNewObjectWithRef method: "); CreateNewObjectWithRef(ref pen); Console.WriteLine($"After CreateNewObjectWithRef method: "); Console.ReadKey(); > > 

В первом методе мы не используем ключевое слово ref . Значение изменяется, потому что мы передаем копию адреса, в котором хранится исходное значение. Во втором методе исходное значение остается прежним. Это потому, что мы создаем новый объект внутри метода, таким образом выделяется новый адрес памяти. Но в третьем методе мы используем ключевое слово ref , и исходное значение изменяется. Зачем? Потому что с ref ключевым словом мы копируем тот же адрес в новый объект.

Резюме

Теперь мы знаем, как использовать ключевые слова ref и out с типами значений и ссылок. Это довольно полезная функция в C#, поэтому знание того, как работать с этими ключевыми словами, является преимуществом для разработчиков.

В следующем посте мы поговорим о рекурсии и рекурсивных методах рекурсии и рекурсивных методах.

ref в сравнении с out в C#

Ключевые слова Ref и out в C# используются для передачи аргументов внутри метода или функции. Оба слова указывают на то, что аргумент/параметр передается по ссылке. По умолчанию параметры передаются в метод по значению. Используя эти ключевые слова ( ref и out ), мы можем передать параметр по ссылке.

Ключевое слово ref

Ключевое слово ref передает аргументы по ссылке. Это означает, что любые изменения, внесенные в этот аргумент в методе, будут отражены в этой переменной, когда управление вернется к вызывающему методу.

Пример кода

public static string GetNextName(ref int id) < string returnText = "Next-" + id.ToString(); id += 1; return returnText; >static void Main(string[] args)

Вывод

Ключевое слово out

Ключевое слово out передает аргументы по ссылке. Это очень похоже на ключевое слово ref .

Пример кода

public static string GetNextNameByOut(out int id) < string returnText = "Next-" + id.ToString(); return returnText; >static void Main(string[] args)

Вывод

Ref в сравнении с Out

Параметр или аргумент должен быть сначала инициализирован, прежде чем он будет передан в ref .

Инициализация параметра или аргумента перед передачей его в out не является обязательной.

Не требуется присваивать или инициализировать значение параметра (который передается по ref ) перед возвратом в вызывающий метод.

Вызываемый метод обязан присвоить или инициализировать значение параметра (который передается в out ) перед возвратом в вызывающий метод.

Передача значения параметра по Ref полезна, когда вызываемый метод также должен модифицировать передаваемый параметр.

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

Инициализация значения параметра перед его использованием в вызывающем методе не обязательна.

Значение параметра должно быть инициализировано в вызывающем методе перед его использованием.

Когда мы используем REF , данные могут передаваться двунаправленно.

Когда мы используем OUT , данные передаются только однонаправленно (от вызываемого метода к вызывающему методу).

И ref , и out по-разному обрабатываются во время выполнения программы, а во время компиляции они обрабатываются одинаково.

Свойства не являются переменными, поэтому они не могут быть переданы в качестве параметра out или ref .

Ключевое слово Ref / Out и перегрузка методов

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

Пример кода

public static string GetNextName(ref int id) < string returnText = "Next-" + id.ToString(); id += 1; return returnText; >public static string GetNextName(out int id)

Вывод при компиляции кода:

Однако перегрузка методов возможна, когда один метод принимает аргумент ref или out , а другой принимает тот же аргумент без ref или out .

Пример кода

public static string GetNextName(int id) < string returnText = "Next-" + id.ToString(); id += 1; return returnText; >public static string GetNextName(ref int id)

Резюме

Ключевые слова out и ref полезны, когда мы хотим вернуть значение в тех же переменных, которые были переданы в качестве аргумента.

Материал подготовлен в рамках специализации «C# Developer». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.

  • Блог компании OTUS
  • Программирование
  • C#

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *