Speak.Me Учить иностранные слова

C#: переменные и параметры

Переменная — область памяти, в которой храниться изменяемое значение. Понятие переменных включает в себя локальные переменные, параметры, свойства классов, и элементы массива.

Стек (Stack) и хип (Heap)

Переменные и константы хранятся в стеке или хипе. Стек (стопка) — блок памяти для хранения локальных переменных и параметров. Стек логически разрастается и сужается при входе и выходе из функции: при входе (вызове) в стек добавляются параметры и локальные переменные, а при выходе они удаляются из стека.

Хип (куча) — блок памяти, в котором хранятся объекты, т.е. экземпляры ссылочных типов. Всякий раз при создании нового объекта он помещается в хип, и возвращается ссылка на объект. Во время выполнения программы хип заполняется по мере создания новых объектов. Сборщик мусора периодически удаляет объекты из хипа, чтобы избежать переполнения памяти. Объект подлежит удалению сразу после того, как на него перестает ссылаться хотя бы одна существующая переменная.

Экземпляры значимых типов и ссылки на объекты размещаются там где они были объявлены. Если экземпляр объявлен как свойство объекта или элемент массива, он храниться в хипе.

В C# нельзя явно удалить объект как это можно сделать в других языках. Вместо этого сборщик мусора удаляет объекты оставшиеся без ссылки.

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

Явное присвоение

C# реализует политику явного присвоения. Это означает, что:

  • локальные переменные должны быть объявлены до использования
  • при вызове метода (функции) ему должны быть переданы значения всех параметров
  • всем остальным переменным (свойствам объектов, элементам массива) автоматически присваивается значение по умолчанию

Значение по умолчанию

Экземпляры всех классов имеют значение по умолчанию. Для предопределенных типов это результат бинарного обнуления памяти:

  • null для ссылочных типов
  • 0 для числовых типов и типа enum
  • '\0' для типа char
  • false для типа bool

С помощью ключевого слова default можно задать значение по умолчанию для любого типа. Значение по умолчанию для пользовательских типов такое же как значение по умолчанию для каждого из его полей.

Параметры

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

Передача по ссылке и по значению. Модификаторы ref и out

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

Присвоение p нового значения не изменяет значения x, т.к. p и x хранятся в разных сегментах памяти.

При передаче аргумента ссылочного типа по значению копируется ссылка, а не сам объект.

В этом примере метод Foo взаимодействует с тем же объектом, что и метод Main, но с помощью разных ссылок на объект. Другими словами, sb и fooSB — разные переменные, ссылающиеся на один и тот же объект. Поскольку fooSB — копия ссылки, присвоение ей значения null не затрагивает переменную sb (однако если бы fooSB была объявлена с модификатором ref, то sb стала бы тоже равна null).

Чтобы передать аргумент по ссылке нужно использовать модификатор параметра ref.

В этом примере, т.к. p и x ссылаются на один и тот же сегмент памяти, присвоение нового значения p изменяет значение x.

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

Модификатор out также как и ref служит для передачи параметра по ссылке, но с двумя отличиями:

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

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

Модификатор params

Модификатор params может быть указан для последнего параметра метода, что позволяет передать в метод любое число параметров одного и того же типа. Тип параметра при этом должен быть объявлен как массив.

Передать аргументы при вызове метода можно двумя способами: как обычные аргументы через запятую или как один массив:

Факультативные параметры

Начиная с версии C# 4.0 методы, конструкторы и индексаторы могут объявлять факультативные (optional) параметры. Параметр считается факультативным если при его объявлении указано значение по умолчанию. Факультативные параметры можно опустить при вызове метода.

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

Значение по умолчанию факультативного параметра должно быть либо константой, либо не принимающим аргументов конструктором какого-либо из значимых типов. Факультативные параметры не могут передаваться по ссылке, соответственно их нельзя помечать модификатором ref или out. Обязательные параметры должны предшествовать факультативным и при объявлении метода и при его вызове. Исключение составляют параметры с модификатором params — они всегда должны быть последними.

Именованные аргументы

Аргументы можно идентифицировать не только по позиции, но и по имени. Именованные аргументы могут следовать в любом порядке. Также можно смешивать именованные аргументы с обычными (позиционными), но именованные должны идти последними. Особенно удобно использовать именованные аргументы в случае факультативных параметров.

Var — автоматическое определение типа

Часто переменные объявляются и инициализируются в один шаг. Если компилятор может предугадать тип переменной исходя из инициализирующего ее выражения, можно использовать ключевое слово var вместо указания типа переменной. Несмотря на то, что тип переменной явно не указывается, ей нельзя в последующем присвоить значение другого типа.