Я отредактировал ваш пример кода, чтобы он действительно мог воспроизвести ошибку.
Проблема здесь в том, что, хотя struct
кажется допустимым неуправляемым типом, при вложении его в универсальный тип он становится «сконструированным типом», который считается управляемым типом. Это связано с тем, что полный тип вашего struct
фактически включает параметр типа, а универсальные типы всегда являются управляемыми типами. т.е. тип не просто MyStruct
, а скорее a.b<T>.MyStruct
, где T
- некоторый тип.
Из спецификации языка C# 5, "10.3.8.6 Вложенные типы в универсальных классах":
Каждое объявление типа, содержащееся в объявлении универсального класса, неявно является объявлением универсального типа.
"4.4 Составные типы" гласит:
имя-типа может идентифицировать сконструированный тип, даже если оно не указывает параметры типа напрямую. Это может произойти, когда тип вложен в объявление универсального класса, а тип экземпляра содержащего объявления неявно используется для поиска имени. В небезопасном коде сконструированный тип нельзя использовать как неуправляемый тип.
И из "18.2 Типы указателей":
референтный тип указателя должен быть неуправляемым типом. неуправляемый тип – это любой тип, который не является ссылочным типом или сконструированным типом, а также не содержит ссылочный тип или сконструированный тип. поля типа на любом уровне вложенности.
Другими словами, спецификация языка ясно дает понять, что MyStruct
является "сконструированным типом", и что вам не разрешено иметь указатели на сконструированные типы.
Что касается того, почему спецификация делает эти ограничения, я не разработчик языка, и поэтому я не могу дать окончательный ответ на этот вопрос. Тем не менее, мне кажется безопасным предположить, что основная проблема здесь заключается в том, что для сконструированного типа теоретически возможно, чтобы тип не поддавался проверке при компиляции как безопасный для кода unsafe
.
В вашем примере параметр типа T
не используется в MyStruct
. Но это могло бы быть, и это было бы явно плохо в контексте указателя unsafe
.
Интуитивно я предположил бы, что теоретически компилятор может провести дополнительный анализ, чтобы убедиться, что MyStruct
можно рассматривать как строго неуправляемый тип, но а) я могу легко ошибиться в этом (дизайнеры языков и составители компиляторов знают гораздо больше о том, что может ошибаться в таких ситуациях, чем я), и б) даже если это теоретически возможно, это было бы дополнительным и значительным усложнением в спецификации языка и написании любого компилятора C#.
Этот последний пункт является ИМХО достаточным оправданием для разработчиков языка, чтобы просто исключить его. В конце концов, многие, если не большинство типов, вложенных в универсальный тип, в любом случае будут использовать параметр универсального типа, поэтому полезность такого дополнительного анализа и снисходительности, вероятно, ограничена.
person
Peter Duniho
schedule
04.09.2016
string
, который не является. - person Reinstate Monica   schedule 04.09.2016Nullable<T>
— это тип значения, такой же, какint
или любой определяемый пользователемstruct
, и работает точно так же с точки зрения хранения. И вы объединяете семантику типа (тип значения и ссылочный тип) с хранилищем (стек и куча). Эти две концепции на самом деле почти полностью не связаны между собой, несмотря на их взаимодействие друг с другом. - person Peter Duniho   schedule 04.09.2016Nullable<T>
вообще не включает бокс, и в коде, опубликованном в вопросе, нет бокса. Да, упакованный тип значения хранится в куче, но тогда это уже не тип значения; это ссылочный тип, который содержит тип значения. - person Peter Duniho   schedule 04.09.2016