Важное различие между ValueTypes и ссылочными типами состоит в том, что типы значений имеют эту "семантику значений". DateTime, Int32 и все другие типы значений не имеют идентичности, Int32 «42» по существу неотличим от любого другого Int32 с тем же значением.
Все значения типа "объекты" существуют либо в стеке, либо как часть объекта ссылочного типа. Один особый случай - когда вы приводите экземпляр типа значения к объекту или интерфейсу - это называется «боксом», и он просто создает фиктивный объект ссылочного типа, который содержит только значение, которое может быть извлечено обратно («распаковано») .
Типы ссылок, с другой стороны, имеют идентичность. «new Object ()» не равен никаким другим «new Object ()», потому что они являются отдельными экземплярами в куче GC. Некоторые ссылочные типы предоставляют метод Equals и перегруженные операторы, так что они ведут себя более как значения, например. Строка "abc" равна другой строке "abc", даже если на самом деле это два разных объекта.
Таким образом, когда у вас есть ссылка, она может содержать адрес действительного объекта или может быть нулевой. Когда объекты типа значения все ноль, они просто ноль. Например. целое число ноль, число с плавающей точкой, логическое значение false или DateTime.MinValue. Если вам необходимо различать «ноль» и «значение отсутствует / ноль», вам нужно использовать либо отдельный логический флаг, либо, что еще лучше, использовать класс Nullable в .NET 2.0. Это просто значение плюс логический флаг. В CLR также есть поддержка, так что бокс Nullable с HasValue = false приводит к пустой ссылке, а не в штучной структуре с false + ноль, как если бы вы реализовали эту структуру самостоятельно.