C# 为什么可以';t结构包含可为空的循环引用?

C# 为什么可以';t结构包含可为空的循环引用?,c#,.net,struct,circular-reference,C#,.net,Struct,Circular Reference,我理解为什么结构不能包含导致逻辑内存问题的循环引用,但为什么可空引用不能绕过这个限制?例如: struct Foo { Foo? bar; } 显然,如果不小心,这很容易导致堆栈溢出和循环引用,但是bar不应该是指向另一个Foo实例的指针,并且默认为null?或者(更有可能)我不明白可空值类型在内存中是如何排列的 (我的背景知识主要包括来自的信息。)不,不完全是。可空值类型实际上是nullable的一个实例,其值类型作为泛型参数。问号只是一个简写 Nullable是一种结构,因此是一种

我理解为什么结构不能包含导致逻辑内存问题的循环引用,但为什么可空引用不能绕过这个限制?例如:

struct Foo
{
    Foo? bar;
}
显然,如果不小心,这很容易导致堆栈溢出和循环引用,但是
bar
不应该是指向另一个
Foo
实例的指针,并且默认为
null
?或者(更有可能)我不明白可空值类型在内存中是如何排列的


(我的背景知识主要包括来自的信息。)

不,不完全是。可空值类型实际上是
nullable
的一个实例,其值类型作为泛型参数。问号只是一个简写


Nullable
是一种结构,因此是一种值类型。因为它保留了对
Foo
结构的引用,所以仍然有一个由值类型组成的循环引用。

结构是值类型。因此,嵌套结构创建了一个内存结构,该结构占用无限量的内存。类是引用类型。因此,嵌套类创建的内存结构可能是无限的,但在初始化时,它仍然很小。

编译器正在遍历结构以确定是否存在循环

虽然结构中包含的引用类型将放在堆中,编译器在查找循环时会对它们进行不同的处理,但可为null类型的真正类型是可为null的结构。因此编译器看到一个结构可以为null,并将其视为循环引用

有一种方法可以解决这个问题-从接口继承:

public interface IFoo
{
}

public struct Foo : IFoo
{
    IFoo Foo;
}
由于接口是一个间接层次,编译器将把您的结构视为引用类型。

Nullable
是一个如下所示的结构(不包括构造函数等):


现在希望这是一个更明显的问题:)

Foo?条形图

Nullable<Foo> bar;
可空条;
Nullable
是一个大致如下所示的结构:

struct Foo
{
    Foo barValue;
    bool hasBarValue;
}
public struct Nullable<T> where T : struct
{
    private readonly T value;
    private readonly bool hasValue;
    //..
}
public结构可为null,其中T:struct
{
私有只读T值;
私有只读布尔值;
//..
}

Foo
的情况下,
Nullable
将保存一个
Foo
,这反过来又保存一个
Nullable
,这反过来…

正如您可能意识到的那样,一个结构不能有循环引用,因为当您在内存中放置该结构时,必须为其每个成员在该结构中包含存储。循环定义需要无限量的存储:

  • 具有两个
    Int32
    成员的结构需要8个字节(
    2*sizeof(Int32)
    );类似地,具有四个
    Int32
    成员的结构需要16个字节
  • 如果一个结构
    S
    有两个
    Int32
    成员加上一个
    S
    成员,它将需要
    2*sizeof(Int32)+sizeof(S)
  • 但是如果
    sizeof(S)=2*sizeof(Int32)+sizeof(S)
    ,我们有无限递归,我们不能为结构分配内存;因此,递归定义是非法的
现在,假设
sizeof(Nullable)=sizeof(bool)+sizeof(T)
(参见Jon Skeet的答案)。用这个定义考虑结构<代码>代码>:< /p>
struct S
{
    int _someField;
    S? _someOtherField;
}
在这种情况下,
sizeof(S)=sizeof(Int32)+sizeof(null)

sizeof(null)
替换为
sizeof(bool)+sizeof(S)
,我们得到

sizeof(S)=sizeof(Int32)+sizeof(bool)+sizeof(S)


再一次,无限递归。

正如我所怀疑的那样-我的问题是不知道
Nullable
在内存中是如何排列的。现在这就更有意义了@RoyiNamir:是的-想想它会是什么样子,因为
Foo
是一种值类型…我理解这一点-我不知道
Nullable
是一种泛型结构,而不是指向
Foo
的指针。
struct S
{
    int _someField;
    S? _someOtherField;
}