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

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

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

Пример:

Struct

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

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

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

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

Недостатки:

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

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

Тип ссылки:

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

Пример:

Класс

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

Сохранено в куче

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

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

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

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

Недостатки:

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

Ответ 3

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

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

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

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

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

var a = "Hello";

компьютер выполнит следующее:

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

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

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

var a = 1;

компьютер выполнит следующее:

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

Ответ 4

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

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

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

Когда вы делаете такой оператор:

Dim A as Integer
DIm B as Integer

A = 3
B = A 

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

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

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

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

Предположим, что вы создали класс с именем 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 указывают на SAME LOCATION на управляемой куче.

Теперь СОХРАНИТЕ ЭТУ ситуацию:

Dim p1 As clsPerson
Dim p2 As clsPerson

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

p2 = p1

p2.Name = "Janis Joplin"

В этой ситуации вы создали один новый экземпляр класса Person в Managed Heap с указателем p1 на стеке, который ссылается на объект, и снова присвоил свойству Name экземпляра объекта значение "Jim Morrison", Затем вы создали другой указатель 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 OR p2 = New clsPerson перед выполнением нового задания.

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

p2.Name = "Jimi Hendrix"

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

Оба msgBoxes вернут "Jimi Hendrix"

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

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

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

Типы значений спускаются из System.ValueType. Тип ссылки спускается из System.Object.

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

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

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

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

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

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

Ответ 9

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

Предположим, что у меня есть две переменные 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, потому что оба по-прежнему относятся к "объекту ID # 19531", который по-прежнему остается тем же автомобилем, что и всегда был.

Ответ 10

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

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

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

Ответ 11

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

Ответ 12

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

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

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

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

Ответ 13

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

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

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

  • Сохраняет фактическое значение.

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

Тип ссылки:

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

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

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

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

Ответ 14

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

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

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

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