В чем разница между ссылочным типом и типом значения в с #?


100

Один парень задал мне этот вопрос пару месяцев назад, и я не мог его подробно объяснить. В чем разница между ссылочным типом и типом значения в C #?

Я знаю , что типы значений int, bool, floatи т.д. , и ссылочные типы delegate, interfaceи т.д. Или это не так, тоже?

Вы можете мне профессионально объяснить это?


3
В качестве небольшого примечания, я думаю, что вопрос задают о C #, но на самом деле он касается C # + .NET. Вы не можете анализировать C # без анализа .NET. Я не буду повторно ставить вопрос, потому что могут быть некоторые моменты, которые нужно сделать при анализе одного без анализа другого (итераторы и замыкания, я смотрю на вас)
xanatos

@xanatos, это наиболее подходящий вопрос о CLI, который является общим для C #, VB.Net и Net. Должен быть тег для CLI, но CLI используется для чего-то другого. Есть CLR, но это реализация, а не стандарт.
user34660

Ответы:


172

Ваши примеры немного странно , потому что в то время int, boolи floatопределенные типов, интерфейсы и делегаты виды типа - так же , как structи enumявляются видами типов значений.

Я написал письмо на объяснение ссылочных типов и типов значений в этой статье . Я был бы рад дополнить все, что вас смущает.

Версия "TL; DR" - это думать о том, каково значение переменной / выражения определенного типа. Для типа значения значение - это сама информация. Для ссылочного типа значение является ссылкой, которая может иметь значение NULL или может быть способом перехода к объекту, содержащему информацию.

Например, представьте переменную как лист бумаги. На нем могло быть написано значение «5» или «ложь», но на нем не мог быть мой дом ... он должен был иметь направление к моему дому. Эти направления являются эквивалентом ссылки. В частности, у двух человек могут быть разные листы бумаги с одинаковыми указаниями к моему дому - и если один человек будет следовать этим указаниям и покрасить мой дом в красный цвет, то второй человек тоже увидит это изменение. Если бы у них обоих были отдельные фотографии моего дома на бумаге, то один человек, раскрашивающий их бумагу, вообще не изменил бы бумагу другого человека.


2
Важно отметить, что существует три различных основных типа семантики, которые может предложить вещь: неизменяемая семантика, семантика изменяемых значений и семантика изменяемых ссылок. Концептуально вид семантики, которую реализует вещь, ортогонален тому, хранится ли она как отдельный объект кучи или как переменная / поле (структура). На практике, хотя структуры, которые не раскрывают свои поля, могут реализовывать любую семантику, тот факт, что .net допускает беспорядочное совместное использование ссылок на кучу, означает, что объекты кучи не могут реализовать семантику изменяемых значений.
supercat

Я не понял этого бита - while int, bool and float are specific types, interfaces and delegates are kinds of type - just like struct and enum are kinds of value types. Что вы имеете в виду под int, bool - конкретными типами? Все в C #, например int, bool, float, class, interface, delegate, является типом (точнее, типом данных). Типы данных в C # разделены на «ссылочный тип» и «тип значения». Тогда почему вы говорите, что int - это особый тип, а интерфейс - это разновидность типа?
RBT

2
@RBT: типы данных не просто разделяются на «ссылочный тип» и «тип значения». Они также разделены на «класс, структура, перечисление, делегат, интерфейс». intявляется структурой, stringявляется классом, Actionявляется делегатом и т. д. Ваш список «int, bool, float, class, interface, delegate» - это список, содержащий разные типы вещей, точно так же, как «10, int» список, содержащий разные вещи.
Джон Скит

@JonSkeet Возможно, ответ на этот пост немного вводит в заблуждение.
RBT

@RBT: Я бы сказал, что это несколько плохо сформулировано, но не ужасно.
Джон Скит

26

Тип значения:

Содержит какое-то значение, а не адреса памяти

Пример:

Struct

Место хранения:

TL; DR : значение переменной сохраняется везде, где оно отменено. Например, локальные переменные находятся в стеке, но когда они объявлены внутри класса в качестве члена, они находятся в куче, тесно связанном с классом, в котором они объявлены.
Дольше : Таким образом, типы значений сохраняются везде, где они объявлены. Например: значение an intвнутри функции как локальная переменная будет храниться в стеке, в то время как значение in int, объявленное как член в классе, будет сохранено в куче с классом, в котором оно объявлено. Тип значения на Тип жизни класса точно такой же, как у класса, в котором он объявлен, и почти не требует работы сборщика мусора. Хотя это более сложно, я бы сослался на книгу @JonSkeet " C # In Depth "Память в .NET »для более краткого пояснения.

Преимущества:

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

Недостатки:

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

  2. Поскольку классы пропускаются. Он теряет все преимущества

Тип ссылки:

Содержит адрес памяти значения, а не значения

Пример:

Класс

Место хранения:

Хранится в куче

Преимущества:

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

  2. Когда размер переменной больше, подходит ссылочный тип

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

Недостатки:

Больше ссылок на работу при выделении и разыменовании при чтении значения. Дополнительная перегрузка для сборщика мусора


5
Не обязательно верно, что ссылочные типы хранятся в куче, а типы значений - в стеке. Прочтите yoda.arachsys.com/csharp/memory.html, если хотите узнать больше.
Rhys

1
В этом ответе много недоразумений. Пожалуйста, прочтите CLR Джеффа Рихтерса через C #. Типы значений хранятся в стеке потоков и не подлежат сборке мусора (GC) - они не имеют ничего общего с GC. Типы ссылок хранятся в управляемой куче и, следовательно, подлежат GC. Если тип ссылки имеет корневую ссылку, он не может быть собран и продвигается вверх по поколениям, 0, 1 и 2. Если у него нет корневой ссылки, он может быть собран с помощью мусора, и затем он проходит через этот процесс, называемый воскрешением, где он убивают и возвращают к жизни, а затем, наконец, собирают.
Джереми Томпсон

13

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

Ссылка обычно связана с указателем. Это означает, что адрес памяти, в котором находится ваша переменная, фактически содержит другой адрес памяти фактического объекта в другом месте памяти.

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

Представьте себе компьютерную память - это набор расположенных в ряд абонентских ящиков (начиная с абонентского ящика 0001 и заканчивая абонентским ящиком n), которые могут содержать что-то внутри. Если почтовые ящики не делают этого за вас, попробуйте хеш-таблицу, словарь, массив или что-то подобное.

Таким образом, когда вы делаете что-то вроде:

var a = "Привет";

компьютер сделает следующее:

  1. выделить память (скажем, начиная с ячейки памяти 1000 для 5 байтов) и поставить H (на 1000), e (на 1001), l (на 1002), l (на 1003) и o (на 1004).
  2. выделить где-нибудь в памяти (скажем, по адресу 0500) и присвоить его переменной a.
    Так что это что-то вроде псевдонима (0500 - это).
  3. присвоить значение в этой ячейке памяти (0500) 1000 (где строка Hello начинается в памяти). Таким образом, переменная a содержит ссылку на фактическую начальную ячейку памяти строки «Hello».

Тип значения будет содержать фактическую вещь в своей ячейке памяти.

Таким образом, когда вы делаете что-то вроде:

var a = 1;

компьютер сделает следующее:

  1. выделить место в памяти, скажем, в 0500, и присвоить его переменной a (тот же псевдоним)
  2. поместите в него значение 1 (в ячейке памяти 0500).
    Обратите внимание, что мы не выделяем дополнительную память для хранения фактического значения (1). Таким образом, фактически хранится фактическое значение , поэтому он называется типом значения.

1
Возможно, вас заинтересует blogs.msdn.com/b/ericlippert/archive/2009/02/17/…
Джон Скит

@Jon, ну, такого рода аннулирование того, что я говорил, LOL. Но, как я уже сказал, это сильно упрощено, чтобы получить некоторое понимание между двумя типами, что в моем случае я нашел полезным. По крайней мере, так я себе это представлял :).
Джимми Чандра

8

Это из моего сообщения с другого форума около двух лет назад. Хотя языком является vb.net (в отличие от C #), концепции типа значения и ссылочного типа единообразны во всем .net, и примеры все еще актуальны.

Также важно помнить, что в .net ВСЕ типы технически являются производными от базового типа Object. Типы значений предназначены для того, чтобы вести себя как таковые, но, в конце концов, они также наследуют функциональность объекта базового типа.

A. Типы значений - это просто: они представляют собой отдельную область в памяти, где хранится дискретное ЗНАЧЕНИЕ. Типы значений имеют фиксированный размер памяти и хранятся в стеке, который представляет собой набор адресов фиксированного размера.

Когда вы делаете подобное заявление:

Dim A as Integer
DIm B as Integer

A = 3
B = A 

Вы сделали следующее:

  1. Создано 2 места в памяти, достаточных для хранения 32-битных целочисленных значений.
  2. Поместил значение 3 в выделение памяти, назначенное A
  3. Поместил значение 3 в распределение памяти, назначенное для B, присвоив ему то же значение, что и для A.

Значение каждой переменной существует отдельно в каждой ячейке памяти.

Б. Типы ссылок могут быть разных размеров. Следовательно, они не могут храниться в «стеке» (помните, стек представляет собой набор выделений памяти фиксированного размера?). Они хранятся в «управляемой куче». Указатели (или «ссылки») на каждый элемент в управляемой куче сохраняются в стеке (как адрес). Ваш код использует эти указатели в стеке для доступа к объектам, хранящимся в управляемой куче. Поэтому, когда ваш код использует ссылочную переменную, он фактически использует указатель (или «адрес» области памяти в управляемой куче).

Допустим, вы создали класс с именем clsPerson со строкой Property Person.Name.

В этом случае, когда вы делаете такое заявление:

Dim p1 As clsPerson
p1 = New clsPerson
p1.Name = "Jim Morrison"

Dim p2 As Person

p2 = p1

В приведенном выше случае свойство p1.Name вернет «Джим Моррисон», как и следовало ожидать. Свойство p2.Name ТАКЖЕ вернет «Джим Моррисон», как и следовало ожидать. Я считаю, что и p1, и p2 представляют разные адреса в стеке. Однако теперь, когда вы присвоили p2 значение p1, как p1, так и p2 указывают на ОДИН МЕСТО в управляемой куче.

Теперь рассмотрите эту ситуацию:

Dim p1 As clsPerson
Dim p2 As clsPerson

p1 = New clsPerson
p1.Name = "Jim Morrison"

p2 = p1

p2.Name = "Janis Joplin"

В этой ситуации вы создали один новый экземпляр класса person в управляемой куче с указателем p1 в стеке, который ссылается на объект, и снова присвоили свойству Name экземпляра объекта значение «Джим Моррисон». Затем вы создали еще один указатель p2 в стеке и указали его на тот же адрес в управляемой куче, что и на адрес p1 (когда вы сделали присвоение p2 = p1).

А вот и поворот. Когда вы присваиваете свойству Name p2 значение «Janis Joplin», вы меняете свойство Name для объекта, на который ссылаются как p1, так и p2, так что если вы выполнили следующий код:

MsgBox(P1.Name)
'Will return "Janis Joplin"

MsgBox(p2.Name)
'will ALSO return "Janis Joplin"Because both variables (Pointers on the Stack) reference the SAME OBJECT in memory (an Address on the Managed Heap). 

Это имело смысл?

Последний. Если вы сделаете ЭТО:

DIm p1 As New clsPerson
Dim p2 As New clsPerson

p1.Name = "Jim Morrison"
p2.Name = "Janis Joplin"

Теперь у вас есть два разных объекта Person. Однако, как только вы сделаете ЭТО снова:

p2 = p1

Вы снова указали на «Джима Моррисона». (Я не совсем уверен, что случилось с объектом в куче, на который ссылается p2 ... Я ДУМАЮ, что теперь он вышел за рамки. Это одна из тех областей, где, надеюсь, кто-то может меня поправить ...). -EDIT: Я ВЕРЮ, поэтому вы должны установить p2 = Nothing ИЛИ p2 = New clsPerson перед выполнением нового назначения.

Еще раз, если вы сейчас сделаете ЭТО:

p2.Name = "Jimi Hendrix"

MsgBox(p1.Name)
MsgBox(p2.Name)

Оба msgBoxes теперь будут возвращать "Jimi Hendrix"

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

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


Я не знаю, почему вы не получили голосов за. Хороший ответ, помог мне разобраться с ясными простыми примерами.
Гарри

Что касается концепции типа значения и ссылочного типа, они единообразны во всем .net, они фактически определены в спецификации Common Language Infrastructure (CLI), стандарте Ecma 335 (также стандарте ISO). Это стандарт для стандартной части .Net. Стандарт Ecma 334 (также стандарт ISO) - это язык C #, и в нем явно указано, что реализации C # должны либо полагаться на CLI, либо поддерживать альтернативный способ получения минимальных функций CLI, требуемых этим стандартом C # . Однако VB.Net не является стандартом, он является собственностью Microsoft.
user34660

5

тип данных значения и ссылочный тип данных

1) значение (содержит данные напрямую), но ссылка (относится к данным)

2) по значению (каждая переменная имеет свою копию), но
по ссылке (более чем переменная может ссылаться на некоторые объекты)

3) по значению (операционная переменная не может влиять на другую переменную), но по ссылке (переменная может влиять на другие)

4) типы значений (int, bool, float), но ссылочные типы (массив, объекты класса, строка)


2

Тип значения:

  • Фиксированный размер памяти.

  • Хранится в памяти стека.

  • Имеет фактическое значение.

    Ex. int, char, bool и т. д.

Тип ссылки:

  • Нефиксированная память.

  • Хранится в памяти кучи.

  • Содержит адрес памяти фактического значения.

    Ex. строка, массив, класс и т. д.


1

«Переменные, основанные на типах значений, непосредственно содержат значения. Присвоение переменной одного типа значения другому копирует содержащееся значение. Это отличается от назначения переменных ссылочного типа, которые копируют ссылку на объект, но не на сам объект». из библиотеки Microsoft.

Вы можете найти более полный ответ здесь и здесь .


1
Мне не нравится это объяснение, потому что похоже, что присваивание работает по-разному для ссылочных типов и типов значений. Это не так. В обоих случаях он делает значение "целевой" переменной равным выражению - значение копируется. Разница есть в том , что значение - для ссылочных типов, значение , которое копируется является ссылкой. Тем не менее, это все еще значение переменной.
Джон Скит,

Я согласен с вами, и я уже знал, что все может быть иначе, как вы можете прочитать в этой статье . Но я просто передаю руководство Microsoft по этому вопросу, а также о том, как вы обычно читаете в книгах. Пожалуйста, не вини меня! :)
Лукас С.

О, конечно ... в документации MSDN есть много фрагментов, в которых можно найти ошибки :)
Джон Скит,

1

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

Поэтому, если вы копируете ссылочную переменную, вы копируете только ссылку / указатель на реальные данные где-нибудь в памяти. Если вы копируете тип значения, вы действительно клонируете данные в памяти.


0

С эзотерической точки зрения это, вероятно, неверно, но для простоты:

Типы значений - это значения, которые обычно передаются «по значению» (таким образом, копируя их). Ссылочные типы передаются «по ссылке» (таким образом, давая указатель на исходное значение). Стандарт .NET ECMA не дает никаких гарантий относительно того, где хранятся эти «вещи». Вы можете создать реализацию .NET без стека или без кучи (второй вариант будет очень сложным, но вы, вероятно, сможете, используя волокна и множество стеков)

Структуры относятся к типу значений (int, bool ... являются структурами или, по крайней мере, моделируются как ...), классы имеют ссылочный тип.

Типы значений происходят от System.ValueType. Тип ссылки происходит от System.Object.

Теперь ... В конце концов, у вас есть Тип значения, "ссылочные объекты" и ссылки (в C ++ они будут называться указателями на объекты. В .NET они непрозрачны. Мы не знаем, что они собой представляют. С нашей точки зрения, они являются «ручками» объекта). Эти длины похожи на типы значений (они передаются по копии). Таким образом, объект состоит из объекта (ссылочного типа) и нуля или более ссылок на него (которые аналогичны типам значений). Когда есть нулевые ссылки, GC, вероятно, соберет их.

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

В случаях типа значения, которые помещаются в кучу, потому что они находятся в функции итератора, асинхронной функции или на которые ссылается закрытие, если вы посмотрите скомпилированный файл, вы увидите, что компилятор создал класс для размещения этих переменных , и класс создается при вызове функции.

Я не умею писать длинные вещи, и у меня есть дела поважнее в моей жизни. Если вам нужна "точная" "академическая" "правильная" версия, прочтите ЭТО:

http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx

Уже 15 минут ищу! Это лучше, чем версии msdn, потому что это сжатая «готовая к использованию» статья.


1
Это неправильно более чем эзотерически. Я бы сказал, что это в корне неверно - потому что значения ссылочного типа также передаются по значению; просто значение является ссылкой, а не объектом. См. Pobox.com/~skeet/csharp/parameters.html . Да, и локальные переменные тоже могут оказаться в куче, например, если они захвачены или являются частью блока итератора.
Джон Скит,

Блоки итераторов преобразуются в классы, поэтому «за вами» находятся «поля класса». То же самое и с закрытием. Да ... Я забыл написать различие между «указателем» (ссылкой) и «указателем»
xanatos

@xanatos: Конечно, это поля класса после компиляции, но они все еще локальные переменные в исходном коде. Я бы также не назвал сами ссылки «типами значений» - я думаю, что знаю, откуда вы, но я не думаю, что это хорошая идея мутить воду таким образом.
Джон Скит,

@jon Да ... Это третий тип, потому что указатели "непрозрачны" в .net и не являются производными от ValueType. Но они больше похожи на типы значений, чем на ссылки. Вы можете "реферировать" и "убирать" их. Пришлось замутить воду, потому что "кто-то" должен был придраться к работе итераторов.
xanatos

Глядя на статью, на которую я сейчас указываю, я обнаружил: «Существует три типа значений: (1) экземпляры типов значений, (2) экземпляры ссылочных типов и (3) ссылки. (Код в C # не может управлять экземпляры ссылочных типов напрямую; он всегда делает это через ссылку. В небезопасном коде типы указателей обрабатываются как типы значений для целей определения требований к хранению их значений. ) ".
xanatos

0

Самый простой способ думать о ссылочных типах - рассматривать их как «идентификаторы объектов»; единственное, что можно делать с идентификатором объекта, - это создавать его, копировать, запрашивать или изменять тип объекта или сравнивать два на равенство. Попытка сделать что-либо еще с идентификатором объекта будет рассматриваться как сокращение для выполнения указанного действия с объектом, на который ссылается этот идентификатор.

Предположим, у меня есть две переменные X и Y типа Car - ссылочный тип. Y имеет «ID объекта № 19531». Если я скажу «X = Y», это приведет к тому, что X будет содержать «ID объекта № 19531». Обратите внимание, что ни у X, ни у Y нет машины. Автомобиль, также известный как «ID объекта № 19531», хранится в другом месте. Когда я скопировал Y в X, все, что я сделал, это скопировал идентификационный номер. Теперь предположим, что я сказал X.Color = Colors.Blue. Такое заявление будет рассматриваться как инструкция найти «объект ID # 19531» и покрасить его в синий цвет. Обратите внимание, что хотя X и Y теперь относятся к синему автомобилю, а не к желтому, это утверждение фактически не влияет на X или Y, потому что оба по-прежнему относятся к «объекту с идентификатором № 19531», который по-прежнему остается тем же автомобилем, что и он. всегда было.


0

Типы переменных и ссылочное значение легко применять и хорошо применять к модели предметной области, что облегчает процесс разработки.

Чтобы развеять миф о количестве «типов значений», я прокомментирую, как это обрабатывается на платформе. NET, в частности, в C # (CSharp) при вызове APIS и отправке параметров по значению, по ссылке, в наших методах и функциях, а также о том, как правильно обрабатывать проходы этих значений.

Прочтите эту статью Значение и справочник по типу переменной в C #


К сожалению, это сайт вопросов и ответов только на английском языке = \. Однако спасибо за попытку ответить. Пожалуйста, создавайте полные ответы со ссылками только в качестве вспомогательных (но не в качестве полного устойчивого ответа). Пожалуйста, посмотрите, как ответить .
Джесси

0

Предположим v, это выражение / переменная типа значения и выражение / переменная rссылочного типа

    x = v  
    update(v)  //x will not change value. x stores the old value of v

    x = r 
    update(r)  //x now refers to the updated r. x only stored a link to r, 
               //and r can change but the link to it doesn't .

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


0

Прежде чем объяснять различные типы данных, доступные в C #, важно упомянуть, что C # - это строго типизированный язык. Это означает, что каждая переменная, константа, входной параметр, тип возвращаемого значения и вообще каждое выражение, оценивающее значение, имеет тип.

Каждый тип содержит информацию, которая будет встроена компилятором в исполняемый файл в виде метаданных, которые будут использоваться средой CLR для обеспечения безопасности типов при выделении и освобождении памяти.

Если вы хотите узнать, сколько памяти выделяет конкретный тип, вы можете использовать оператор sizeof следующим образом:

static void Main()
{
    var size = sizeof(int);
    Console.WriteLine($"int size:{size}");
    size = sizeof(bool);
    Console.WriteLine($"bool size:{size}");
    size = sizeof(double);
    Console.WriteLine($"double size:{size}");
    size = sizeof(char);
    Console.WriteLine($"char size:{size}");
}

Вывод покажет количество байтов, выделенных каждой переменной.

int size:4
bool size:1
double size:8
char size:2

Информация, относящаяся к каждому типу:

  • Требуемое место для хранения.
  • Максимальные и минимальные значения. Например, тип Int32 принимает значения от 2147483648 до 2147483647.
  • Базовый тип, от которого он наследуется.
  • Место, где будет выделяться память для переменных во время выполнения.
  • Виды разрешенных операций.
  • Члены (методы, поля, события и т. Д.), Содержащиеся в типе. Например, если мы проверим определение типа int, мы найдем следующую структуру и члены:

    namespace System
    {
        [ComVisible(true)]
        public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<Int32>, IEquatable<Int32>
        {      
            public const Int32 MaxValue = 2147483647;     
            public const Int32 MinValue = -2147483648;
            public static Int32 Parse(string s, NumberStyles style, IFormatProvider provider);    
            ... 
        }  
    }

Управление памятью Когда в операционной системе запущено несколько процессов и объема оперативной памяти недостаточно, чтобы вместить все это, операционная система сопоставляет части жесткого диска с оперативной памятью и начинает хранить данные на жестком диске. Операционная система будет использовать специальные таблицы, в которых виртуальные адреса сопоставлены с соответствующими физическими адресами для выполнения запроса. Эта возможность управления памятью называется виртуальной памятью.

В каждом процессе доступная виртуальная память организована в следующие 6 разделов, но для актуальности этой темы мы сосредоточимся только на стеке и куче.

Стек Стек представляет собой структуру данных LIFO (последний пришел - первым ушел), размер которой зависит от операционной системы (по умолчанию для компьютеров ARM, x86 и x64 резерв Windows составляет 1 МБ, а в Linux - от 2 МБ до 8 МБ в зависимости от версия).

Этот раздел памяти автоматически управляется ЦП. Каждый раз, когда функция объявляет новую переменную, компилятор выделяет новый блок памяти размером с его размер в стеке, а когда функция завершается, блок памяти для переменной освобождается.

Куча. Эта область памяти не управляется ЦП автоматически, и ее размер больше, чем размер стека. Когда вызывается ключевое слово new, компилятор начинает поиск первого свободного блока памяти, который соответствует размеру запроса. и когда он его находит, он помечается как зарезервированный с помощью встроенной функции C malloc () и возвращает указатель на это место. Также возможно освободить блок памяти с помощью встроенной функции C free (). Этот механизм вызывает фрагментацию памяти и должен использовать указатели для доступа к правому блоку памяти, он медленнее, чем стек для выполнения операций чтения / записи.

Пользовательские и встроенные типы. Хотя C # предоставляет стандартный набор встроенных типов, представляющих целые числа, логические значения, текстовые символы и т. Д., Вы можете использовать такие конструкции, как struct, class, interface и enum, для создания ваших собственных типов.

Пример настраиваемого типа с использованием конструкции struct:

struct Point
{
    public int X;
    public int Y;
};

Типы значений и ссылочные типы Мы можем разделить тип C # на следующие категории:

  • Типы значений
  • Типы ссылок

Типы значений Типы значений являются производными от класса System.ValueType, а переменные этого типа содержат свои значения в выделенной им памяти в стеке. Две категории типов значений - это структура и перечисление.

В следующем примере показан член типа boolean. Как видите, явной ссылки на класс System.ValueType нет, это происходит потому, что этот класс наследуется структурой.

namespace System
{
    [ComVisible(true)]
    public struct Boolean : IComparable, IConvertible, IComparable<Boolean>, IEquatable<Boolean>
    {
        public static readonly string TrueString;
        public static readonly string FalseString;
        public static Boolean Parse(string value);
        ...
    }
}

Ссылочные типы С другой стороны, ссылочные типы не содержат фактических данных, хранящихся в переменной, а содержат адрес кучи, в которой хранится значение. Категории ссылочных типов - это классы, делегаты, массивы и интерфейсы.

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

В следующем примере показаны члены универсального типа List.

namespace System.Collections.Generic
{
    [DebuggerDisplay("Count = {Count}")]
    [DebuggerTypeProxy(typeof(Generic.Mscorlib_CollectionDebugView<>))]
    [DefaultMember("Item")]
    public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
    {
        ...
        public T this[int index] { get; set; }
        public int Count { get; }
        public int Capacity { get; set; }
        public void Add(T item);
        public void AddRange(IEnumerable<T> collection);
        ...
    }
}

Если вы хотите узнать адрес памяти определенного объекта, класс System.Runtime.InteropServices предоставляет способ доступа к управляемым объектам из неуправляемой памяти. В следующем примере мы собираемся использовать статический метод GCHandle.Alloc () для выделения дескриптора строки, а затем метод AddrOfPinnedObject для получения ее адреса.

string s1 = "Hello World";
GCHandle gch = GCHandle.Alloc(s1, GCHandleType.Pinned);
IntPtr pObj = gch.AddrOfPinnedObject();
Console.WriteLine($"Memory address:{pObj.ToString()}");

Выход будет

Memory address:39723832

Ссылки Официальная документация: https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=vs-2019


-1

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

См. Стандарт 33 ECMA , Common Language Infrastructure (CLI) . Интерфейс командной строки также стандартизирован ISO. Я бы дал ссылку, но для ECMA мы должны загрузить PDF-файл, и эта ссылка зависит от номера версии. Стандарты ISO стоят денег.

Одно отличие состоит в том, что типы значений могут быть помещены в коробку, а ссылочные типы - нет. Бывают исключения, но они довольно технические.

Типы значений не могут иметь конструкторы экземпляров или финализаторы без параметров, и они не могут ссылаться на себя. Обращение к себе означает, например, что если существует тип значения Node, то член Node не может быть Node . Я думаю, что в спецификациях есть другие требования / ограничения, но если это так, то они не собраны в одном месте.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.