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

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

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

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

14 ответов


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

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

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

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


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

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

пример:

Struct

хранение:

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

плюсы:

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

недостатки:

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

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

ссылка типа:

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

пример:

класс

хранение:

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

плюсы:

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

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

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

недостатки:

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


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

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

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

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

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

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

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

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

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

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

var a = 1;

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

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

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

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

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

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

Dim A as Integer
DIm B as Integer

A = 3
B = A 

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

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

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

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

скажем, вы создали класс с именем clsPerson, с человеком строкового свойства.Имя

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

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

Dim p2 As Person

p2 = p1

в случае выше, p1.Название собственности вернет "Джим Моррисон", как и следовало ожидать. Р2.Свойство " имя " также вернется "Джим Моррисон", как вы бы Iintuitively ожидать. Я считаю, что и 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 . . . Я думаю, что теперь он вышел за рамки. Это одна из таких областей где hopefullly кто-то может задать мне прямо . . .). - EDIT: я считаю, что именно поэтому вы должны установить p2 = Nothing или p2 = New clsPerson перед выполнением нового задания.

еще раз, если вы сейчас это сделаете:

p2.Name = "Jimi Hendrix"

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

теперь оба msgBoxes вернут "Jimi Hendrix"

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

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


тип данных value и ссылочный тип данных

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

2) в стоимостью( каждая переменная имеет свою собственную копию) но!--15--> в ссылка (больше, чем переменная может ссылаться на некоторые объекты)

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

4) типы значений are(int, bool, float) но ссылка типа are (array , Class objects , string )


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

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


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

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


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

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

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

типы значений происходят из системы.ValueType. Ссылочный тип спускается из системы.Объект.

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

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

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

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

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

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


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

предположим, что у меня есть две переменные X и Y типа Car--ссылочный тип. Y случается держать "object ID #19531". Если я скажу "X=Y", это заставит X удерживать"идентификатор объекта #19531". Обратите внимание, что ни X, ни Y не держат автомобиль. Автомобиль, иначе известный как" объект ID #19531", хранится в другом месте. Когда я скопировал Y В X, все, что я сделал, это скопировал идентификационный номер. Теперь предположим, что я говорю X. цвет=цвета.Синий. Такое заявление будет рассматриваться как инструкция, Чтобы найти "object ID#19531" и покрасить его в синий цвет. Обратите внимание, что, хотя X и Y теперь относятся к синему автомобилю, а не к желтому, утверждение не фактически влияют на X или Y, потому что оба по-прежнему относятся к "объекту ID #19531", который по-прежнему остается тем же автомобилем, что и всегда.


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

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

читать это статья значение типа переменной и ссылка в C #


предположим 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"). Ссылочный тип varaible хранит только ссылку на метафорическое поле, где находится значение.


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

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

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

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


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

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

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

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

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

Ссылка Типа:

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

  • хранится в куче память.

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

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


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

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

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

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