2016-09-03 2 views
3

При использовании unsafe или fixed ключевом слова в C#, вы можете определить указатели на неуправляемые тип, как byte*int* и т.д. Вы можете также определить указатель на какую-либо структуру, что только содержит неуправляемые типы, например:Объявление указатель на класс определяемых структур, где класс является общим

namespace a 
{ 
    struct MyStruct 
    { 
    int value1; 
    int value2; 
    } 

    class b<T> 
    { 
     unsafe void SomeMethod() 
     { 
     MyStruct* ptr; 
     } 
    } 
} 

Однако, если struct определяется в определение общего класса, я получаю сообщение об ошибке CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type. В чем причина этого ограничения?

UPDATE: Эта ошибка возникает только в том случае, если содержащийся класс является общим. Я до сих пор не вижу причин для ошибки - компилятор может видеть, что структура будет всегда содержит неуправляемые типы, поскольку она не ссылается на общий тип T.

namespace a 
{ 
    class b<T> 
    { 
     struct MyStruct 
     { 
      int value1; 
      int value2; 
     } 

     unsafe void SomeMethod() 
     { 
      MyStruct* ptr; // gives a compiler error 
     } 
    } 
} 
+0

@MachineLearning. Неа. Все поля здесь - типы значений - этот ответ относится к строке, которая не является. – afuna

+0

Просьба предоставить хороший [mcve], который надежно воспроизводит описанную вами ошибку. Существует несколько сценариев, которые могут привести к этой ошибке, но никто, о котором я не знаю, начнет с кода, который вы здесь указали. –

+0

@afuna int in struct может быть неназначенным, поэтому я предполагаю, что его значение будет в куче при назначении и, таким образом, будет подчиняться GC как строка в классе. –

ответ

0

Я отредактировал ваш пример кода, чтобы он мог фактически воспроизвести ошибку.

Проблема заключается в том, что, хотя struct представляется законным неуправляемым типом, путем вложения его в общий тип, он становится «сконструированным типом», который считается управляемым типом. Это связано с тем, что полный тип вашего struct фактически включает параметр типа, а общие типы - это управляемые типы. То есть тип не только MyStruct, но и a.b<T>.MyStruct где T - это какой-то тип.

Из спецификации языка C# 5, «10.3.8.6 Вложенные типы в общих классах»:

Каждый тип декларации, содержащиеся в декларации общего класса неявно общая декларация типа.

«4.4 Построенные типы» гласит:

типа имя-могут идентифицировать конструируемый тип, даже если он не определяет параметры типа непосредственно. Это может произойти, когда тип вложен в объявление универсального класса, а тип экземпляра содержащего объявления неявно используется для поиска имени и hellip; в небезопасном коде построенный тип не может использоваться в качестве неуправляемого типа.

И от "18,2 типов указателей":

& hellip; тип референта указателя должен быть неуправляемого типом. неуправляемого типа любого типа, который не является опорного типа или составным тип, и не содержит опорного типа или построенные поля типа на любом уровне вложенности.

Другими словами, спецификация языка становится ясно, как то, что MyStruct является «построен тип», и что вы не можете иметь указатели на построенных типов.

Что касается того, почему спецификация делает эти ограничения, я не разработчик языка, и поэтому я не могу дать окончательного ответа на это. Тем не менее, мне кажется безопасным предположить, что основная проблема здесь заключается в том, что для построенного типа теоретически возможно, чтобы тип не поддавался проверке при компиляции как безопасный для кода unsafe.

В вашем примере параметр типа T не используется в MyStruct. Но это может быть, и это будет явно плохо в контексте указателя unsafe.

Я интуитивно предположил, что теоретически возможно, чтобы компилятор выполнил дополнительный анализ, чтобы проверить, что MyStruct можно трактовать как неуправляемый тип, но a) я мог легко ошибаться в этом (разработчики языка и писатели-компиляторы знают много больше о том, что может пойти не так, как в подобных ситуациях, чем я), и б) даже если это теоретически возможно, это будет дополнительным и значительным осложнением в спецификации языка и написании любого компилятора C#.

Этот последний момент является обоснованием ИМХО, достаточным для того, чтобы разработчики языка просто исключили его. В конце концов, многие, если не большинство типов, вложенных в общий тип, все равно будут использовать параметр типового типа, поэтому полезность такого дополнительного анализа и снисхождения, вероятно, ограничена.

+1

Спасибо за редактирование. Я скопировал и вставлял и собирался вложить структуру, но, должно быть, испортил ее. Что касается вашего ответа, я бы согласился с тем, что это технически верно по спецификации. Что касается рационального, мне трудно принять его - компилятор всегда проверяет структуру * anyways *, чтобы убедиться, что его поля неуправляемы - было бы проще просто классифицировать поле родового типа как управляемое, а когда нет не бросать ошибку. – afuna

+0

_ «Что касается рационального, мне трудно принять его» _ - Вы профессиональный дизайнер языка? «Обоснование», которое вы ставите под сомнение, - это люди, которые разработали C#, чрезвычайно компетентных экспертов в этой области. Я думаю, что очень вероятно, что у них есть очень веская причина сделать любой тип внутри родового типа для себя считающимся «построенным». Тем не менее, если вы хотите аргументировать рассуждение, вам нужно спорить с людьми, которые разработали язык, а не я. Лично я даю им пользу от сомнений и предполагаю, что если спецификация говорит что-то, для этого есть веская причина. –

+0

Конечно, у них может быть большая причина. Я имел в виду разумное * вы * предположили, что это сложность в спецификации языка - это то, что мне трудно принять, по той причине, что я написал в комментарии. Я ценю, что вы предложили рациональное, хотя вы не дизайнер, и я не вижу проблем в обсуждении упомянутого рационального с помощью * you *. – afuna

Смежные вопросы