2

在 C# 中使用unsafeorfixed关键字时,您可以定义指向非托管类型的指针,例如byte* int*等。您还可以定义指向仅包含非托管类型的任何结构的指针,例如:

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

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

但是,如果泛型类定义中定义,我会得到structerror 。这种限制的原因是什么?CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type

更新:仅当包含类是泛型时才会发生此错误。我仍然看不出错误的原因 - 编译器可以看到该结构将始终包含非托管类型,因为它不引用泛型类型T

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

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

注意:在最终版本中,此功能似乎已添加到 C#:请参阅GitHub 上的此问题

4

1 回答 1

0

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

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

来自 C# 5 语言规范,“10.3.8.6 泛型类中的嵌套类型”

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

“4.4 构造类型”内容如下:

即使没有直接指定类型参数,类型名称也可能标识构造类型这可能发生在一个类型嵌套在泛型类声明中,并且包含声明的实例类型隐式用于名称查找......在不安全的代码中,构造类型不能用作非托管类型

并来自“18.2 指针类型”

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

换句话说,语言规范清楚地表明这MyStruct是“构造类型”,并且不允许您拥有指向构造类型的指针。

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

在您的示例中, type 参数T未用于MyStruct. unsafe但它可能是,这在指针上下文中显然是不好的。

我直觉地猜测编译器在理论上可以进行额外的分析以验证是否MyStruct可以被视为严格的非托管类型,但是a)我很容易错了(语言设计者和编译器编写者对可能发生的事情了解更多在这种情况下比我更错误),b)即使理论上可行,这将是语言规范和任何 C# 编译器的编写中的一个额外且重要的复杂性。

后一点是恕我直言,足以让语言设计者将其排除在外。毕竟,嵌套在泛型类型中的许多(如果不是大多数)类型无论如何都会使用泛型类型参数,因此这种额外分析和宽大处理的用处可能是有限的。

于 2016-09-04T06:50:42.927 回答