Как стать автором
Обновить

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

Небольшое вступление:


Как программист я себя не считаю достаточно опытным для того, чтобы писать довольно сложные программы и при этом не пользоваться дополнительной литературой для более полного представления той среды, которой я пользуюсь. Я как и те, кто читает мои статьи по программированию, также учусь быть профессиональным программистом и при этом читаю довольно много соответствующей литературы. В основе моих публикаций лежат мои собственные умозаключения, которые я получил, читая довольно «мощную» книгу Джеффри Рихтера «CLR via C#. Программирование на платформе Microsoft .NET Framework 4.0 на языке C#». Чем мне нравится эта книга, так это то обилие информации, которое помогает понять не только механизм действия того или иного события, но и сам принцип и те основы, которые нужны для того, чтобы понимать саму суть происходящего, а не просто использовать тот или иной метод, при этом не задумываясь о последствиях его использования. Ведь в конечном счете это влияет на работу самой программы, ее производительности и т.д.

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

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 и так далее.

В следующей статье я опишу как правильно подобрать тип в зависимости от поставленных задач, а также будет рассматриваться упаковка и распаковка значимых типов.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.