Ключевые слова in, out и ref в методах C#

Сегодня разберемся с тем, какие ключевые слова можно использовать в методах C#, в чем их различия, когда надо использовать in, когда ref или out и так далее. Также затронем вопрос об использовании необязательных параметров в методах C#.

Зачем нужны ключевые слова in, out и ref?

Когда только-только начинаешь разбираться с языком программирования, то невольно возникают сотни различных вопросов. Например, зачем нам вообще нужны ключевые слова in, out и ref в методах C#? Можно же просто передавать в метод определенные параметры и получать в ответ какие-то значения. Давайте рассмотрим простой пример. Допустим, пусть наш метод будет выполнять всего одну операцию — наращивать значение параметра на единицу и возвращать новое значение. Метод будет выглядеть у нас вот так:

static int Addition(int a)
{
   a++; 
   return a;
}

Теперь вызовем наш метод в основной программе:

static void Main(string[] args)
{
    Console.WriteLine("Введите любое целое число и нажмите Enter");
    int a = int.Parse(Console.ReadLine());
    Console.WriteLine($"Результат выполнения метода: {Addition(a)}. Значение переменной после выполнения метода: {a}");
   
}

Что выведет на экран наша программа. Смотрим:

Введите любое целое число и нажмите Enter
1
Результат выполнения метода: 2.
Значение переменной после выполнения метода: 1

Как так? Мы же знаем, что арифметический оператор ++ наращивает значение переменной на 1, но программа нам выдает, что переменная, которую мы передали в параметрах метода осталась неизменной, а результат — верный? На самом деле, здесь в метод мы передаем не саму переменную, а её копию. Значение копии увеличивается на 1 и возвращается нам, а сама переменная остается такой же какой и была.  Такой способ передачи параметров называется передачей по значению.

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

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

Ключевое слово ref позволяет передавать аргумент (параметр) по ссылке, а не по значению. Если мы передаем параметр по ссылке, то этот параметр (переменную) можно изменить внутри метода, например, перепишем наш  метод Addition:

static int Addition(ref int a)
{
    a++;
    return a;
}

Теперь параметр a передается по ссылке, значит внутри метода мы можем его изменить. Так как в описании метода мы использовали ключевое слово ref, то и  при вызове метода мы также должны использовать ref при передаче параметров (обратите внимание на третью строку метода где вызывается Addition()):

static void Main(string[] args)
{
    Console.WriteLine("Введите любое целое число и нажмите Enter");
    int a = int.Parse(Console.ReadLine());
    Console.WriteLine($"Результат выполнения метода: {Addition(ref a)}. Значение переменной после выполнения метода: {a}");
   
}

Теперь результат работы программы будет следующий:

Введите любое целое число и нажмите Enter

5

Результат выполнения метода: 6. Значение переменной после выполнения метода: 6

Как видите, передача параметра по ссылке позволяет изменять значение переменной в теле метода.

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

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

int b;
Addition(ref b);

то компилятор сообщит нам об ошибке:

Ошибка CS0165 Использование локальной переменной «b», которой не присвоено значение.

так как переменная b объявлена, но не инициализирована. С ключевым словом out инициализацию переменной можно не проводить перед её передачей в метод и вот такой код не вызовет ошибки:

static int Addition(out int a)
{
    a = 0;//присвоили начальное значение
    a++; //нарастил на 1
    return a;
}

static void Main(string[] args)
{
  int b;
  Console.WriteLine($"Результат выполнения метода: {Addition(out b)}. Значение переменной после выполнения метода: {b}");
}

Начиная с версии C# 7.0 переменные, передаваемые по ссылке, можно определять сразу в вызове метода, то есть вызов метода Addition() в предыдущем примере можно переписать вот так:

Console.WriteLine($"Результат выполнения метода: {Addition(out int b)}. Значение переменной после выполнения метода: {b}");

Здесь мы сразу при вызове метода определили переменную b.

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

Кроме выходных параметров метода, объявляемых с модификатором out, в C# можно также определить входные параметры, передаваемые по ссылке с использованием ключевого слова in. Суть ключевого слова in следующая — параметр с модификатором in передается по ссылке, но внутри метода его изменять нельзя. Может возникнуть резонный вопрос: зачем нам тогда такой модификатор? Можно же просто убрать всякие ключевые слова и передавать параметр по значению. Как говориться, дьявол кроется в деталях.

Когда используется передача параметра по значению, то внутри метода создается точная копия переменной, когда по ссылке — в метод передается только адрес в памяти где лежит значение. Когда мы имеем дело с переменными простых типов, типа 5, 2, 99.9, то особых проблем нет — на современных компьютерах мы даже не заметим,  что программа «отъела»лишние байты памяти.  А теперь представим,  что в метод передается структура «весом» с сотню мегабайт. Передача по значению приведет к тому, что у нас в памяти будет сама переменная структуры в 100 Мб и в методе её точная копия ещё на 100 Мб и такой расход памяти уже можно будет ощутить.  Поэтому для таких случаев и можно использовать ключевое слово in — передать в метод только ссылку на область памяти где лежит значение и, при этом, запретить это значение изменять.


Итого

Итого, сегодня мы познакомились с ключевыми словами (модификаторами) для параметров методов: ref, out, in и научились их использовать в зависимости от поставленных задач.

Подписаться
Уведомить о
guest
2 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии