Типы-значения не сводятся к примитивным типам и могут состоять из нескольких переменных. В C# для объявления value type используется ключевое слово struct, как в следующем примере:
struct RectVal { public int x, y, cx, cy; }
Важно понять, что тип-значение содержит само значение переменной, а не ссылку на него. Это экономит память, так как нет необходимости хранить таблицу виртуальных методов и дополнительный указатель на значение. Кроме того, использование типов-значений улучшает производительность, так как отпадает потребность в лишнем разыменовывании указателя и создании новой копии объекта в "куче". Но с другой стороны, типы-значения имеют множество ограничений. Например, они не могут наследовать от других типов и от них также нельзя ничего унаследовать - они являются "запечатанными", sealed. Поэтому можно считать, что типы-значения в целом ведут себя как встроенные типы (кстати, часто рекомендуют не делать типы-значения больше 12-16 байт).
Важно понимать, что при присваивании типов-значений происходит копирование значения, поэтому типы-значения редко используются, если их надо часто передавать в качестве параметров.
Сравнение типов-значений имеет более интересную механику: все типы-значения унаследованы от System.ValueType, который предоставляет такие же методы, как и System.Object, за исключением метода Equals, который выдает True, если значения совпадают, и GetHashCode, который учитывает значение переменной. При создании собственных value types настойчиво рекомендуется переопределять эти методы на свои собственные.