Урок посвящен типам-значениям данных и их особенностям и правилам использования.
- Тип-значение (value type) в C#
- Создание переменной типа-значения
- Присваивание объектов типов-значений
- Сравнение на равенство объектов типов-значений
Тип-значение (value type) в C#
В рамках этого урока мы познакомимся поближе с типами-значениями.
О типах значениях важно помнить следующее:
- экземпляры этих типов располагаются в стеке, но если они являются частью ссылочного типа, то в куче;
- они не обрабатываются сборщиком мусора (только вместе с объектом, в состав которого могут входить);
- как только метод (блок кода), в котором они объявлены, завершается, экземпляры удаляются из памяти;
- если вы присваиваете значение одной переменной типа-значения другой, то создается новый экземпляр, в который копируются все поля из исходного объекта;
- тип-значение не может быть базовым типом, то есть от него нельзя наследоваться;
- при сравнении экземпляров типов через оператор
==
(или методEquals()
) сравниваются значения полей, а не ссылки.
К типам-значениям относятся:
- группа из набора примитивных типов (числа,
bool
,char
); - перечисления (
enum
); - структуры (
struct
); - типы значений, допускающие
null
; - типы значений кортежей (
ValueTuple
); - структуры записи (
struct record
).
В рамках урока подробно остановимся на примитивных типах-значениях (про другие типы более детально расскажем позже).
К примитивным типам-значениям относятся:
- целочисленные типы;
- типы с плавающей точкой;
- тип
bool
для представления логических значений (true
иfalse
); - тип
char
для представления символьных значений.
Создание переменной типа-значения
Рассмотрим, что происходит при создании переменной типа-значения, на примере переменной типа int
.
int n = 3;
При выполнении этой строки в стеке выделяется память под переменную num
.
При модификации значения переменной, в памяти (в соответствующей ячейке) изменится содержимое.
При завершении работы блока кода (метода), память, выделенная под локальные переменные, очищается.
Присваивание объектов типов-значений
В предыдущем уроке, посвященном ссылочным типам, мы выяснили, что при присваивании значения ссылочного типа, происходит копирование ссылки на объект, который располагается в памяти (куче), при этом сам объект остается тем же.
Person p1 = new Person() { Name = "John" }; // Person - это класс Person p2 = p1;
При присваивании типов-значений происходит создание нового экземпляра типа и копирование значений свойств (полей) из исходного значения в новое. Все это будет храниться в стеке.
Создадим объект тип Point
, присвоим его другому объекту:
var pnt1 = new Point() { X = 1.2, Y = 3.4 }; // Point - это структура var pnt2 = pnt1; Console.WriteLine($"{pnt1.X}, {pnt1.Y}"); // 1.2, 3.4 Console.WriteLine($"{pnt2.X}, {pnt2.Y}"); // 1.2, 3.4
Изменим значение поля X
у pnt1
:
pnt1.X = 5.6; Console.WriteLine($"{pnt1.X}, {pnt1.Y}"); // 5.6, 3.4 Console.WriteLine($"{pnt2.X}, {pnt2.Y}"); // 1.2, 3.4
При этом значение полей у pnt2
не измениться, так как эти переменные связаны с разными областями памяти в стеке.
Сравнение на равенство объектов типов-значений
При сравнении объектов ссылочного типа между собой через метод Equals()
, если у соответствующего класса он не переопределен, сравниваются ссылки, то есть проверяется: указывают ли переменные на один и тоже объект в памяти, таким образом, проверяется тождественность объектов. Если метод Equals()
переопределен, то результат сравнения зависит от заложенной в него логики.
Сравнение экземпляров типов-значений в случае если метод Equals()
не переопределен, выполняется как сравнение значений свойств (полей).
Создадим набор переменных типа Point
и сравним их между собой:
var a = new Point() { X = 1.2, Y = 3.4 }; var b = new Point() { X = 1.2, Y = 3.4 }; var c = new Point() { X = 5.6, Y = 3.4 }; Console.WriteLine(a.Equals(b)); // True Console.WriteLine(a.Equals(c)); // False
Если Вы хотите больше узнать про язык C#, приглашаем Вас на наш курс “C#. Базовый уровень“.