Урок посвящен типам-значениям данных и их особенностям и правилам использования.
- Тип-значение (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#. Базовый уровень“.