В чем разница между ссылочным типом и типом значения в c #? - PullRequest
89 голосов
/ 20 февраля 2011

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

Я знаю, что типы значений int, bool, float и т. Д., А ссылочные типы delegate, interface и т. Д. Или это тоже неправильно?

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

Ответы [ 14 ]

155 голосов
/ 20 февраля 2011

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

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

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

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

22 голосов
/ 11 июля 2013

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

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

Пример:

Структура

Хранение:

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

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

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

Недостатки:

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

  2. Поскольку классы пропущены. Это приводит к потере всех дополнительных преимуществ

Тип ссылки:

Содержит адрес памяти значения, не являющегося значением

Пример:

Класс

Хранение:

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

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

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

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

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

Недостатки:

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

13 голосов
/ 20 февраля 2011

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

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

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

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

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

var a = "Hello";

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

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

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

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

var a = 1;

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

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

Это из моего поста с другого форума, около двух лет назад. В то время как язык vb.net (в отличие от C #), понятия «тип значения и справочный тип» едины во всем .net, и примеры все еще сохраняются.

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

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

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

Dim A as Integer
DIm B as Integer

A = 3
B = A 

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

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

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

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

Допустим, вы создали класс с именем 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"

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

А вот и поворот. Когда вы присваиваете свойству Name значение p2 значение «Janis Joplin», вы изменяете свойство Name для объекта REFERENCED на оба параметра 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"

Теперь у вас есть два отдельных объекта персонажа. Однако, в ту минуту, когда вы делаете это снова:

p2 = p1

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

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

p2.Name = "Jimi Hendrix"

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

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

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

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

4 голосов
/ 01 января 2015

тип данных значения и тип справочных данных

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

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

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

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

1 голос
/ 04 апреля 2017

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

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

1 голос
/ 20 февраля 2011

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

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

0 голосов
/ 18 мая 2018

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

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

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

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

0 голосов
/ 07 мая 2018

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

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

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

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

    Пример. int, char, bool и т.д ...

Тип ссылки:

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

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

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

    Пример. строка, массив, класс и т. Д. *

0 голосов
/ 28 декабря 2015

Проще говоря, типы значений передаются по их значению, а ссылочные типы - по ссылке (адресу памяти).

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

Но изменения, внесенные в ссылочные параметры внутри вызываемого метода, отразятся на изменениях переменных, объявленных в вызывающем методе.

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

...