C# 声明指向类为泛型的类定义结构的指针

C# 声明指向类为泛型的类定义结构的指针,c#,interop,unsafe-pointers,C#,Interop,Unsafe Pointers,在C#中使用unsafe或fixed关键字时,可以定义指向非托管类型的指针,如byte*int*等。还可以定义指向仅包含非托管类型的任何结构的指针,例如: namespace a { struct MyStruct { int value1; int value2; } class b<T> { unsafe void SomeMethod() { MyStruct* ptr;

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

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

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

注意:在最终版本中,此功能似乎被添加到了C中:请参见GitHub。

我编辑了您的代码示例,以便它能够真实地再现错误

这里的问题是,
struct
似乎是合法的非托管类型,但通过将其嵌套在泛型类型中,它将成为“构造类型”,被视为托管类型。这是因为
结构的完整类型实际上包括类型参数,泛型类型始终是托管类型。也就是说,类型不仅仅是
MyStruct
,而是
a.b.MyStruct
,其中
t
是某种类型

根据C#5语言规范,“泛型类中的10.3.8.6嵌套类型”:

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

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

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

以及“18.2指针类型”:

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

换句话说,语言规范明确指出,
MyStruct
是一种“构造类型”,并且不允许有指向构造类型的指针

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

在您的示例中,
MyStruct
中未使用类型参数
T
。但它可能是,而且在
不安全的
指针上下文中,这显然是不好的

我直觉地猜测,编译器在理论上有可能进行额外的分析,以验证
MyStruct
是否可以被视为严格的非托管类型,但a)我很容易在这方面出错(语言设计者和编译器编写者比我更了解在这种情况下可能出现的错误),b)即使在理论上是可能的,这也会给语言规范和任何C#编译器的编写带来额外的、重大的复杂性


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

@MachineLearning。不。这里的所有字段都是一个值类型-该答案指的是
字符串
,而不是。请提供一个可靠地再现您描述的错误的好字段。有许多情况可能会产生该错误,但据我所知,没有一种情况会以您在此处显示的代码开头。@afuna结构中的int可以取消赋值,因此我猜在赋值时它的值将在堆中,因此会像类中的字符串一样受GC的约束。@Machine:“结构中的int可以取消赋值,所以我猜它的值将在堆中”--这句话毫无意义。值类型可能在堆中,也可能不在堆中,这取决于它们的位置(例如,类中的字段与局部变量),但值是否已分配与它的存储位置或堆中的内存是否已分配无关。好吧,你是对的,没有实际需要拒绝此代码。但是Eric Lippert总是有一个完美的借口,当C#编译器和语言中的角情况是主题时,这需要额外的代码来加倍-检查结构成员是否不使用类型参数。必须编写、维护和记录的额外代码。考虑到解决方法非常简单,丢失的功能非常有限,程序员不方便的可能性非常低,让他们添加此功能将非常困难。您可以证明请试一试。谢谢你的编辑。我已经复制并粘贴了结构,打算嵌套它,但一定把它搞砸了。关于你的回答,我同意按照规范,它在技术上是正确的。至于rational,我发现很难接受-编译器总是检查结构,以确保它的字段是非托管的-这会更容易o只需将泛型类型的字段分类为托管字段,在不存在时不要抛出错误。“关于rational,我发现很难接受”--你是专业的语言设计师吗“你所质疑的是设计C#的人,他们是该领域极有能力的专家。我认为他们很可能有很好的理由让泛型类型中的任何类型被认为是“构造的”。这就是说,如果你想论证理由,你需要和设计语言的人争论,而不是我。就我个人而言,我给了他们怀疑的好处,并且假设如果规范说了什么,有一个很好的理由。当然,他们可能有一个很好的理由。我指的是你所建议的理性——这是l
namespace a
{   
    class b<T>
    {
        struct MyStruct 
        {
            int value1;
            int value2;
        }

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