如何存储int或其他“;C#值类型”;在堆上(使用C#)

本文关键字:使用 类型 何存储 存储 int 其他 | 更新日期: 2023-09-27 18:29:21

我通过Troelsen的Pro C#书自学C#。

我熟悉堆栈和堆以及C#如何存储这类东西。在C++中,每当我们使用new时,我们都会收到一个指向堆上某个东西的指针。然而,在C#中,new的行为对我来说似乎不同:

  • 当与像int这样的值类型一起使用时,使用new似乎只调用int默认构造函数,但这样的int的值仍然存储在堆栈中

我知道,无论是否使用new,所有对象/结构等都存储在堆中。

所以我的问题是:如何在堆上实例化int?(这与"装箱"有关吗?)

如何存储int或其他“;C#值类型”;在堆上(使用C#)

您可以将任何值类型装箱为System.Object类型,以便将其存储在托管堆上:

int number = 1;
object locatedOnTheHeap = number;

另一个问题是你为什么需要这个。

这是MSDN必读论文中的一个经典例子:装箱和拆箱(C#编程指南)

CLR对值类型进行装箱时,会将该值包装在对象并将其存储在托管堆上。装箱用于将值类型存储在垃圾收集堆中。Boxing是将值类型隐式转换为类型对象或到由该值类型实现的任何接口类型。装箱一个值类型在堆上分配对象实例并复制值到新对象中。

我知道所有对象/结构等都存储在堆上

顺便说一句,IIRC有时会JIT优化代码,因此像int这样的值类型对象存储在CPU寄存器中,而不是堆栈中。

我不知道你为什么要这样做,但是,理论上你确实可以装箱你的价值。您可以通过将int装箱到一个对象(这是一个引用类型,将被放置在堆栈上:

object IAmARefSoIWillBeOnHeap = (object)1;

*正如sll所说,您不需要(object),因为它将是一个隐式强制转换。这仅仅是出于学术原因,来展示正在发生的事情。

这是一篇关于引用与值类型的好文章,这是堆与堆栈的区别

  • 作为一个局部变量,通常在堆栈上(但借用Eric Lippert的话,堆栈是一个实现细节,我建议你阅读他在博客上的精彩文章:关于值类型的真相。)
  • 作为类中的字段,它用值类型的大小扩展实例的大小,并占用实例内部的空间

因此,此代码:

var x = new SomeValueType();

是否在堆上为该值类型单独分配一些东西。如果使用匿名方法或类似方法关闭它,则局部变量将被转换为类的字段,并且该类的实例将在堆上分配,但在这种情况下,值类型将作为字段嵌入到该类中。

堆用于引用类型的实例。

然而,你提到了一些关于拳击的事情。您可以将一个值类型值框起来,制作它的副本,并将该副本放在堆上,封装在对象中。

所以这个:

object x = new SomeValueType();

将首先分配值类型,然后将其框入一个对象中,并将对该对象的引用存储在x中。

然而,这样的int的值仍将存储在堆栈上

这不一定是真的。即使是真的,它也只是一个实现细节,而不是语言规范的一部分。主要问题是类型系统不一定与运行时使用的存储机制相关。

在许多情况下,对结构调用new仍然会导致对象不在堆栈中。装箱就是一个很好的例子——当你装箱一个对象时,你基本上是把它推到一个对象中(有效地把它"复制"到堆中),并引用这个对象。此外,任何时候用lambda关闭一个值类型,都会导致"在堆上分配"

话虽如此,我根本不会关注这个问题——这个问题实际上不应该是关于分配中堆栈与堆的问题,而是关于值类型与引用类型的语义和用法的问题。因此,我强烈建议阅读Eric Lippert的《关于价值类型的真相》和Jon Skeet的《参考文献与价值观》。这两篇文章都集中在结构与类语义的重要方面,而不必关注存储。

至于强制在堆上存储int的方法,这里有几个简单的方法:

object one = 1; // Boxing
int two = 2; // Gets closed over, so ends up "on the heap"
Action closeOverTwo = () => { Console.WriteLine(two); }
// Do stuff with two here...
var three = new { Three = 3 }; // Wrap in a value type...

如果你想在堆上使用int,你可以这样做:

object o = 4;

但基本上,你不应该想要那样。C#的设计目的是让你不要去想这些事情。这是一个很好的起点:http://blogs.msdn.com/b/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

所以我的问题是:如何在堆上实例化int?(确实这与"拳击"有关?)

你对对象和结构的理解是正确的。当初始化一个对象或一个结构时,它会进入堆中。