System.ValueType Понимание - PullRequest
       1

System.ValueType Понимание

30 голосов
/ 17 августа 2010

Я пытался создать ValueType.

Я понимаю, что создание структуры поможет мне.

Я также пытался извлечь тип из System.ValueType, который является абстрактным классом.

Но я получил сообщение об ошибке компилятора " .. не может быть производным от специального класса System.ValueType "

Когда я вижу метаданные ValueType, он выглядит как обычный абстрактный класс.

  1. Что сделало его особенным?

  2. Это компилятор C #, который воспринимает его как особенный?

  3. Если да, рекомендуется ли это, как правило, для проектирования компилятора? Я имею в виду, это часть спецификации общего языка?

Ответы [ 7 ]

36 голосов
/ 17 августа 2010

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 состоит в том, что все вышеперечисленное происходит.

3 голосов
/ 17 августа 2010

Структуры являются типами значений.Типы значений являются особыми, потому что они размещаются в стеке, а не в куче.Чтобы «наследовать» от ValueType, вы должны создать структуру.

2 голосов
/ 17 августа 2010

Невозможность получить из ValueType специфична для компилятора C #.Если мы посмотрим на управляемый код C ++:

value class Foo {};
value class Foo : System::ValueType {};

Оба они компилируются и идентичны.Конечно,

ref class Foo : System::ValueType {};

выдаст ошибку C3050: класс ref не может наследоваться от 'System :: ValueType'.
Не уверен, что другие компиляторы допускают.наследуется от ValueType в C #, использует struct, а не class, и компилятор позаботится об этом.

1 голос
/ 17 августа 2010

C # не позволяет типам значений наследоваться от других классов. Типы значений (структура) могут реализовывать интерфейсы.

1 голос
/ 17 августа 2010

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

см. MSDN , чтобы узнать больше

0 голосов
/ 08 декабря 2010

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

[Serializable, ComVisible(true)]
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
{
  ...
}
0 голосов
/ 17 августа 2010
  1. Класс 'расширяет' System.Object ', а' struct 'расширяет' System.ValueType '.Если бы вы могли заставить класс расширять System.ValueType, тогда не было бы особого смысла в ключевом слове struct.

  2. Да

  3. Да.Должен быть только один способ выполнить любую вещь.Как только предоставляются два способа сделать что-то, вы просто все усложняете.Общее правило.

...