ValueType - это маленькая ложь.
Встроенные числовые типы (int, long, byte), char, enums и структуры являются типами значений.
Это означает, что ониимеют разные понятия идентичности и эквивалентности для типов объектов.Если я делаю x = y
, а x и y являются ссылочными типами, то x и y теперь указывают точно на один и тот же объект.Однако, если я x = y
, а x и y являются типами значений, то x и y теперь являются двумя совершенно разными объектами, которые оказываются идентичными.(Это также отражено в ==
и Equals
, хотя это может быть переопределено).
(Здесь люди отвлекаются, говоря о стеке и куче, если они этого еще не сделали,на самом деле это детали реализации, и хотя это важно, это не главное для различия между значениями и ссылочными типами.)
Теперь, в основном это все и хорошо, но одна вещь в ссылочных типах состоит в том, что все они выигрывают от наследованияиз System.Object.Тип значения int на самом деле не очень, и это тоже хорошо, так как во многих отношениях намного лучше, если он будет обрабатываться четырьмя байтами памяти с помощью прекрасных инструкций процессора, которые так хороши в этом.Тем не менее, иногда полезно иметь возможность рассматривать int так, как если бы он также унаследован от System.Object, и вы можете это сделать.
Конечно, это означает, что вы можете делать с int вещи, которые имеют смысл делать только в System.Object, поэтому, когда вы делаете это, int «упаковывается», а затем снова может быть «распакован».
Это здорово, но что если мы захотим сделать что-то конкретное для типов значений?Более того, что, если разработчики CLR сделали (в частности, они хотели получить GetHashCode для типов значений, связанных с описанной выше эквивалентностью на основе значений, а не эквивалентность на основе идентификаторов, которую имеют объекты)?
Для этого у нас есть ValueType.Система рассматривает все типы значений как наследуемые от этого класса, который, в свою очередь, наследует от Object.Enum, в свою очередь, наследует от типа значения, и все типы перечисления наследуются от него, предоставляя некоторые общие функции для всех перечислений.
Итак, если вы когда-нибудь захотите обработать суперкласс всех типов значений, используйте ValueType, но если выхотите на самом деле создать тип значения, создать структуру или перечисление в зависимости от ситуации.
Объяснение общей системы типов:
Структура - это тип значения, который происходит неявноиз System.ValueType, который, в свою очередь, является производным от System.Object.Структура очень полезна для представления значений, чьи требования к памяти невелики, и для передачи значений в качестве параметров по значению в методы со строго типизированными параметрами.В библиотеке классов .NET Framework все примитивные типы данных (Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32 и UInt64) определены как структуры.
Как и классы, структуры определяют как данные (поля структуры), так и операции, которые можно выполнять над этими данными (методы структуры).Это означает, что вы можете вызывать методы для структур, включая виртуальные методы, определенные в классах System.Object и System.ValueType, и любые методы, определенные для самого типа значения.Другими словами, структуры могут иметь поля, свойства и события, а также статические и нестатические методы.Вы можете создавать экземпляры структур, передавать их в качестве параметров, сохранять их как локальные переменные или сохранять их в поле другого типа значения или ссылочного типа.Структуры также могут реализовывать интерфейсы.
Типы значений также отличаются от классов в нескольких отношениях.Во-первых, хотя они неявно наследуются от System.ValueType, они не могут напрямую наследоваться от любого типа.Точно так же все типы значений запечатаны, что означает, что никакой другой тип не может быть получен из них.Они также не требуют конструкторов.
Для каждого типа значения общеязыковая среда выполнения предоставляет соответствующий коробочный тип, который является классом, имеющим то же состояние и поведение, что и тип значения. Экземпляр типа значения упаковывается, когда он передается методу, который принимает параметр типа System.Object. Он распаковывается (то есть преобразуется из экземпляра класса обратно в экземпляр типа значения), когда управление возвращается из вызова метода, который принимает тип значения в качестве параметра ссылки. Некоторые языки требуют использования специального синтаксиса, когда требуется коробочный тип; другие автоматически используют коробочный тип, когда это необходимо. Когда вы определяете тип значения, вы определяете как упакованный, так и распакованный тип.
Странность ValueType состоит в том, что все вышеперечисленное происходит.