在C#中使用unsafe
或fixed
关键字时,您可以定义指向非托管类型的指针,例如byte*
int*
等。您还可以定义指向任何类型的指针仅包含非托管类型的struct,例如:
namespace a
{
struct MyStruct
{
int value1;
int value2;
}
class b<T>
{
unsafe void SomeMethod()
{
MyStruct* ptr;
}
}
}
但是,如果{<1}}在中定义了泛型类定义,则会收到错误struct
。这种限制的原因是什么?
更新:仅当包含类是通用类时才会出现此错误。我仍然没有看到错误的原因 - 编译器可以看到结构总是包含非托管类型,因为它没有引用泛型类型CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type
。
T
答案 0 :(得分:0)
我已经编辑了您的代码示例,以便它可以实际重现错误。
这里的问题是,虽然struct
似乎是合法的非托管类型,但通过将其嵌套在泛型类型中,它变成了#34;构造类型&#34;,这被认为是托管类型。这是因为struct
的完整类型实际上包含类型参数,泛型类型始终是托管类型。即类型不仅仅是MyStruct
,而是a.b<T>.MyStruct
,其中T
是某种类型。
从C#5语言规范,&#34; 10.3.8.6泛型类中的嵌套类型&#34; :
泛型类声明中包含的每个类型声明都是隐式的泛型类型声明。
&#34; 4.4构造类型&#34; 读取:
type-name 可能会识别构造的类型,即使它没有直接指定类型参数。这种情况可能发生在类型嵌套在泛型类声明中,并且包含声明的实例类型隐式用于名称查找...在不安全的代码中,构造的类型不能用作非托管类型
来自&#34; 18.2指针类型&#34; :
...指针的指示类型必须是非托管类型。 非托管类型是任何不是引用类型或构造类型的类型,并且不包含引用类型或构造在任何嵌套级别键入字段。
换句话说,语言规范清楚地表明MyStruct
是一个&#34;构造类型&#34;,并且你不允许有指向构造类型的指针。
至于规范为什么会受到这些限制,我不是语言设计师,因此我无法就此提供明确的答案。但是,对我来说,似乎可以安全地假设这里的主要问题是对于构造类型,理论上可能在编译类型中不能验证类型对unsafe
代码是安全的。
在您的示例中,T
中未使用类型参数MyStruct
。但它可能是,在unsafe
指针上下文中显然会很糟糕。
我直觉地猜测,从理论上讲,编译器可以进行额外的分析以验证MyStruct
可以被视为严格的非托管类型,但是a)我可能很容易就错了(语言)设计师和编译器编写者更多地了解在这种情况下可能出现的问题比我想的更多,并且b)即使它在理论上是可能的,它也会在语言规范和写作中产生额外的重要复杂性。任何C#编译器。
后一点是恕我直言的理由足以让语言设计者排除它。毕竟,嵌套在泛型类型中的许多(如果不是大多数)类型无论如何都会使用泛型类型参数,因此这种额外分析和宽大处理的有用性可能是有限的。