Ссылочные и значимые типы данных в CLR via C# (часть 1)

в 9:47, , рубрики: Без рубрики

Ссылочные и значимые типы.

CLR поддерживает две разновидности типов: ссылочные (reference types) и значимые
(value types). Помимо этих есть еще и примитивые типы(но я их опишу в следующих статьях).
Большинство типов в FCL(Framework Class Library)- ссылочные, но программисты чаще всего используют значимые. В чем между ними разница спросите вы?


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

У переменной значимого типа поля экземпляра размещаются в самой переменной. Поле представляет собой изменяемое или неизменяемое значение. Поле может быть статическим и является частью ТИПА, или же быть экземплярным(нестатическим) и являться частью самого ОБЪЕКТА. Чтобы наиболее полностью понять разницу между объектом и типом, нужно хорошо разбираться в концепциях ООП. Также в отличие от ссылочного типа, память для значимого типа выделяется при этом в стеке потока. Стек потока — это область памяти, которая используется для передачи параметров в методы и хранения определенных в пределах методов локальных переменных. Те, кто может быть знаком с многопоточным выполнением программ, то такой поток еще по-другому называют «Стек пользовательского режима». Его размер всегда равен 1Мб. Чтобы вы правильно поняли, то метод static void Main() это и есть главный поток программы, в котором мы создаем значимые переменные, а также методы с параметрами и без параметров. А ведь эти переменные и параметры надо где-то хранить, вот для этого и используется стек потока.

Так в чем же состоит существенная разница между этими двумя типами. Все кроется в том, как выделяется память для этих двух типов. Как выше было сказано, в одном случае память выделяется в куче, в другом случае в стеке. Так вот, если все типы были бы ссылочными, то скорость работы программы очень резко бы упала. Ведь представьте, что при каждом обращении к типу Int32, то сколько бы раз нужно было бы выделять память в куче при создании переменной. Поэтому для ускорения работы, CLR предлагает нам «облегченные» — значимые типы. В такой переменной нет указателя на экземпляр, поля экземпляра размещаются в самой переменной. При этом переменные не обрабатываются сборщиком мусора. А также момент размещения в стеке достаточно быстр. Предположим мы создаем переменную Int32 — это 32-разрядное значение и среда знает уже изначально, сколько нужно выделить памяти для этой переменной, поэтому выделение происходит моментально.

К ссылочным типам относятся:
  • class
  • interface
  • delegate
  • object
  • string
Значимые типы:
  1. Структуры (struct)
  2. Перечисления (enum)

Структуры делятся на следующие категории:

  • Числовые типы:
  1. Целочисленные типы (sbyte, byte,char,short,ushort,int,uint,long,ulong)
  2. Типы с плавающей точкой (float,double)
  3. decimal (обозначает 128-разрядный тип данных. По сравнению с типом данных с плавающей запятой, тип decimal имеет более точный и узкий диапазон, благодаря чему он походит для финансовых расчетов.)
  • bool (для хранения логических значений, true и false)
  • Пользовательские структуры

Как известно корнем иерархии всех типов, классов и т.д. является класс Object. По умолчанию он всегда явлется базовым классом. В документации .NET Framework сказано, что структуры являются прямыми потомками типа System.ValueType, который является производным в свою очередь от System.Object, при этом метод Equels возвращает true, если значения полей у обоих объектов совпадают. Так же алгоритм метода GetHashCode реализован с учетом значений полей. Но при создании своего значимого типа рекомендуется переопределить оба этих метода. При этом значимые типы являются изолированными в целях безопасности. Поэтому при создании своего собственного значимого типа нельзя в качестве базового указывать другие типы, например Boolean, Char, Int32 и так далее.

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

Автор: Priest512

Источник

Поделиться

* - обязательные к заполнению поля