声明一个指向类定义的结构体的指针,其中类是泛型的



在c#中使用unsafefixed关键字时,可以定义指向非托管类型的指针,如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
        }
    }
}

注意:似乎这个功能是在c#的最终版本中添加的:请参阅GitHub上的这个问题。

我已经编辑了您的代码示例,以便它可以实际再现错误。

这里的问题是,虽然struct看起来是合法的非托管类型,但通过将其嵌套在泛型类型中,它变成了"构造类型",被认为是托管类型。这是因为struct的完整类型实际上包括类型参数,而泛型类型总是托管类型。也就是说,类型不只是MyStruct,而是a.b<T>.MyStruct,其中T是某种类型。

来自c# 5语言规范,"10.3.8.6泛型类中的嵌套类型":

泛型类声明中包含的每个类型声明都是隐式泛型类型声明。

"4.4构造类型"读取:

即使不直接指定类型参数,type-name也可以标识构造类型。这种情况可能发生在类型嵌套在泛型类声明中,并且包含声明的实例类型隐式地用于名称查找& help;在不安全代码中,构造类型不能用作非托管类型

"18.2指针类型":

& help;指针的引用类型必须是非托管类型非托管类型是非引用类型或构造类型的任何类型,并且在任何嵌套级别上都不包含引用类型或构造类型字段。

换句话说,语言规范明确了MyStruct是一个"构造类型",并且不允许有指向构造类型的指针。

至于为什么规范会有这些限制,我不是语言设计者,所以我不能给出一个明确的答案。然而,对我来说,似乎可以安全地假设这里的主要问题是,对于构造类型,理论上可以在编译类型上无法验证类型,因为对unsafe代码是安全的。

在您的示例中,MyStruct中没有使用类型参数T。但它可能是,这在unsafe指针上下文中显然是不好的。

我直觉地想,这在理论上是可能的编译器做额外的分析来验证MyStruct可视为一个严格的非托管类型,但是)我很可能是错的(语言设计者和编译器作者知道更多关于哪些方面可能出现问题比我在这种情况下),和b)即使在理论上是可能的,这将是一个额外的和重大的并发症在语言规范和写作的c#编译器。

后一点对于语言设计者来说是足够的理由来排除它。毕竟,许多(如果不是大多数)嵌套在泛型类型中的类型无论如何都会使用泛型类型参数,因此这种额外分析和宽大处理的有用性可能是有限的。

最新更新