Почему ссылочные типы указателей?
На этой неделе я работал над некоторым кодом на основе отражения, и во время модульного тестирования обнаружилось неожиданное условие: указатели являются ссылочными типами. Код С# typeof(int).MakePointerType().IsClass
возвращает true
.
Я проверил в моем только что полученном стандартном стандарте CLI, и, конечно же, указатели четко определены как ссылочные типы.
Это было удивительно для меня, исходя из фона С++. Я только что предположил, что указатели будут типами значений.
Существует ли конкретная причина, по которой типы указателей являются ссылочными типами, а не типами значений?
Обновление (уточнение)
Говоря о указателях и ссылках, вещи часто путаются в отношении "указателя" и "указателя". Итак, здесь некоторые разъяснения.
Типы могут быть ссылочными типами или типами значений, но переменные немного отличаются. (Извините, у меня не было возможности прочитать мой стандарт CLI, поэтому терминология и концепции могут быть неправильными - исправьте меня, пожалуйста!)
Учитывая этот код (понятия локальной переменной для ссылочных типов):
var x = new MyClass();
var y = x;
Переменные x
и y
не являются ссылочными типами, но они являются ссылками на объект, который является ссылочным типом (MyClass
является ссылочным типом). Другими словами, x
и y
не являются экземплярами ссылочного типа; они относятся только к экземпляру ссылочного типа.
Учитывая этот код (понятия локальной переменной для типов значений):
var x = 13;
var y = x;
Переменные x
и y
представляют собой типы значений экземпляров (или, по крайней мере, действуют как экземпляры).
Итак, мы приходим к этому коду:
var i = 13;
var x = &i;
var y = x;
Если тип указателя является ссылочным типом, тогда я интерпретирую оператор x = &i
:
- Создается экземпляр типа
int*
, указывающий на i
.
- Поскольку указатели являются ссылочными типами, этот экземпляр создается в куче (при условии, что все ссылочные типы помещаются в кучу, деталь реализации).
-
x
- ссылка на этот экземпляр указателя.
- Экземпляр указателя в конечном итоге будет собирать мусор, как и другие ссылочные типы.
- Когда выполняется
y = x
, ссылка копируется. Оба y
и x
относятся к тому же экземпляру объекта-указателя.
Возможно, я полностью ошибаюсь в этой интерпретации.
Исходя из фона С++, для меня было бы разумнее, чтобы указатели были типами значений, поэтому оператор x = &i
просто присваивает адрес i
экземпляру типа значения x
и y = x
копирует значение адреса в y
. В куче не будет создан "объект-указатель".
Ответы
Ответ 1
Я не видел полного ответа, поэтому сейчас я закрываю этот вопрос.
Я вынужден сделать вывод: указатели (например, int *
) фактически являются типами значений; тот факт, что их Type
return true
для IsClass
является ошибкой в спецификации. Я подозреваю, что никто этого не заметил, потому что получение типа указателя - очень редкая операция.
Ответ 2
typeof (int).MakePointerType(). IsPointer
похоже, что существует различие.
Ответ 3
Это всего лишь теория, но имеет ли она какое-то отношение к тому факту, что из-за системы сбора мусора и уплотнения кучи указатели должны корректироваться при перемещении объектов в памяти. Создавая ссылочные типы управляемых указателей, они могут быть перенаправлены так же, как и любая другая ссылка, вместо того, чтобы сделать их особым случаем.
Обновление
Отличная статья Wesner Moise: " Указатели UNDOCUMENTED".
В статье описывается, как управляемые указатели корректируются во время уплотнения кучи.
Ответ 4
Они являются ссылочными типами, потому что они не содержат фактического значения целевого объекта: точно так же, как ссылки, они просто "указывают" на целевой объект.
Ответ 5
Рассмотрим:
MyClass x = new MyClass();
Здесь MyClass является ссылочным типом, и если вы просмотрите отражение, x будет называться ссылочным типом. Но, под капотом, x на самом деле является указателем.