Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 可为空的类型存储在内存中的什么位置?_C#_.net_Nullable - Fatal编程技术网

C# 可为空的类型存储在内存中的什么位置?

C# 可为空的类型存储在内存中的什么位置?,c#,.net,nullable,C#,.net,Nullable,这可能是对问题的后续 内存中存储的可空值类型(int?…)具体在哪里?首先,我认为这很清楚,因为Nullable是struct,它们是值类型。然后我找到了Jon Skeet的文章“”,上面写着: 请注意,值类型变量可以 永远不要将值设为null-它是空的 没有任何意义,因为null是一个 引用类型概念,意思是“ 此引用类型变量的值 不是对任何对象的引用 全部” 看完这段话,我有点困惑。假设我有int?a=零。由于int通常是一种值类型,它是否以某种方式存储在堆栈中的structNullable中

这可能是对问题的后续

内存中存储的可空值类型(
int?
…)具体在哪里?首先,我认为这很清楚,因为
Nullable
是struct,它们是值类型。然后我找到了Jon Skeet的文章“”,上面写着:

请注意,值类型变量可以 永远不要将值设为null-它是空的 没有任何意义,因为null是一个 引用类型概念,意思是“ 此引用类型变量的值 不是对任何对象的引用 全部”


看完这段话,我有点困惑。假设我有
int?a=零。由于
int
通常是一种值类型,它是否以某种方式存储在堆栈中的struct
Nullable
中(我使用了“normal”,因为我不知道值类型变为Nullable时会发生什么情况)?或者这里发生了其他任何事情-可能是在堆中?

请参阅Eric关于结构存储位置的评论。这比我贴的要彻底得多(正确得多)

它的工作方式是nullable有一个布尔值,表示是否已设置该值。从技术上讲,您是正确的,可空值(int,bool)等实际上不是空值。它有一个默认值。只是现在可空类型有一个布尔值,您可以检查该值是否已设置,或者它只是默认值。将
=
=
赋值时,将覆盖
=
=
以设置适当的值

MSDN链接到

另一个描述nullables如何工作的链接:

除了Kevin的答案之外:编译器知道可空类型,并将
==null
检查更改为对“.HasValue”的调用。

可空只能假装为null:

int? a = null;
Debug.Assert((a == null) == (!a.HasValue));
编译器是这一把戏的同谋。一个有趣的结果是:

Nullable<double> b = new Nullable<double>();
Debug.Assert(b == null); //I'm null upon construction!
首先,
Nullable
只是以下内容的简写:

struct Nullable<T> 
{
    bool hasValue;
    T value;
}
struct Nullable
{
布尔值;
T值;
}
加上所有构造函数、访问器等。仅此而已--可为null的int是一个普通int加上一个表示int是否为null的标志。其余的都是将“null”视为有效值的编译器魔法;对于可为null的类型,“null”所做的一切就是使您成为标志设置为false的结构之一

所以现在我们已经解决了这个问题,你的问题是“他们在记忆中去了哪里”?它们与内存中的任何其他结构的位置相同:运行时和编译器认为在内存的生命周期中,它们是最好的位置

大多数结构放在堆上。任何告诉你“结构总是在堆栈上运行”的人实际上并不知道他们在谈论什么;我们的文件没有这样说,这是不真实的。当结构是局部变量或临时变量,且局部变量不在匿名方法或lambda的外部变量上闭合,且局部变量不在迭代器块中时,结构仅在临时内存池(也称为“堆栈”)上运行。在我们的实现中,所有其他结构都放在堆上

还请注意,CLI的实现不需要使用“堆栈”来创建临时池。例如,经典的JScript内存管理器将其临时池存储在堆上。(当然,JScript运行时引擎不是CLI的实现;我只是指出,可以设计一个托管运行时引擎,不将任何用户数据放在“堆栈”上。)逻辑上,它是一个堆栈数据结构,但该数据结构不存储在“堆栈”上,它只是一个分配在堆上的堆栈结构


我不得不问:你为什么在乎?CLR代表您管理内存。为什么您关心可空类型的去向?他们去哪里,他们活得足够长,对你有用;您不必担心这一点。

结构并不总是存储在堆栈上。正确的语句是“未在匿名方法或lambda表达式的外部变量上闭合且不在迭代器块中的结构类型的局部变量存储在桌面CLR的Microsoft实现中的堆栈上。”不要求有称为“堆栈”的数据结构或者所有结构都存储在它上面。结构是类的字段、迭代器块中的局部变量或外部变量存储在堆上。谢谢你详尽的回答。我在乎是因为我好奇。我认为(也许很天真)了解代码背后的实际情况是很有价值的。我不想最终编写出什么神奇的东西。@Ondrej,如果你认为可空编译器支持是神奇的,那么试着用一个包含闭包的lambda表达式编写一个IEnumerable方法,返回结果为yield。在ildasm中打开生成的程序,看看编译器在封面下为您做了什么。一个需要理解的问题不应该回答为“您为什么关心?”@wcpro:当然应该。理解提问的原因是给出符合提问者实际需求的答案的绝对关键!如果提问者出于好奇而提问,那是一回事。如果提问者要根据答案做出技术或商业决策,那完全是另一回事。了解某人想知道的原因是非常重要的,这样答案就可以定制为他们提供正确的信息,以便他们有效地做出决策。@hstg:您询问整数在堆上的时间示例,但只需要不明显的示例。我不知道对你来说什么是显而易见的。但这个问题是错误的。问题应该是变量何时进入堆栈?当int进入堆中时不会,因为int不是进入堆中的东西。任何类型的变量都是堆或堆栈上的变量。你忘记了所有变量中最神奇的一个(你无法模仿的)
struct Nullable<T> 
{
    bool hasValue;
    T value;
}