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
,这反过来…正如您可能意识到的那样,一个结构不能有循环引用,因为当您在内存中放置该结构时,必须为其每个成员在该结构中包含存储。循环定义需要无限量的存储:
- 具有两个
成员的结构需要8个字节(Int32
);类似地,具有四个2*sizeof(Int32)
成员的结构需要16个字节Int32
- 如果一个结构
有两个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;
}