C# 堆栈上是否有声明类型的对象指针?

C# 堆栈上是否有声明类型的对象指针?,c#,.net,clr,C#,.net,Clr,假设我有: class Animal { } class Dog : Animal { } 在主要方法中: Dog dog = new Dog(); Animal animal = dog; 现在堆上有一个Dog实例,堆栈上有两个变量,其中存储了相同的引用。下一步是 //Try to invoke dog.Bark() programatically //Try to invoke animal.Bark() programatically 后者在运行时失败,因为animal没

假设我有:

class Animal { }
class Dog : Animal { }
在主要方法中:

Dog dog = new Dog();
Animal animal = dog;
现在堆上有一个
Dog
实例,堆栈上有两个变量,其中存储了相同的引用。下一步是

   //Try to invoke dog.Bark() programatically
   //Try to invoke animal.Bark() programatically

后者在运行时失败,因为
animal
没有
Bark
方法。所以对于这两个变量,堆栈上一定有不同的东西。导致运行时错误的区别是什么?

引用位于堆栈上,CLR知道它使用的引用类型。引用指向的内存在堆上分配。在您的示例中,两个引用都可以指向内存中的相同位置,但由于引用类型的不同,CLR对它们的解释不同

引用位于堆栈上,CLR知道它使用的引用类型。引用指向的内存在堆上分配。在您的示例中,两个引用都可以指向内存中的相同位置,但由于引用类型的不同,CLR对它们的解释不同

您正确地推断了许多实现细节

在讨论这些细节之前,先介绍一些术语。有三种存储方式:

  • 非托管存储
  • 托管存储
  • 临时储存
非托管存储超出了您的问题范围。托管存储就是我们所说的“堆”。临时存储是“堆栈”或寄存器(如果抖动很巧妙且寄存器可用),但作为一个简化的假设,让我们忽略寄存器,只需将临时存储池称为“堆栈”

有四种类型:

  • 非托管指针
  • 值类型
  • 引用,又名,托管指针
  • 引用类型的实际实例
非托管指针超出了问题的范围。C#允许您直接操作引用(“托管指针”)和值类型;引用类型实例的内容仅通过引用进行操作,并且在CLR实现中始终位于堆上。(如果jitter有足够的智能知道对象不需要垃圾收集,并且无法在方法中生存,那么没有任何东西可以阻止它在堆栈上创建引用类型的实例,但实际上据我所知,我们的jitter不会这样做。)

其他三种东西可以根据需要放在堆栈或堆上,具体取决于它们的生命周期

在我的主方法中,会创建一个Dog实例,并将其分配给名为Dog的变量。我知道堆上发生了什么,假设它位于地址0x00FFFF

您(正确地)假设托管引用作为平面32位地址空间中的地址实现。当然,CLR的实现不需要使用原始地址作为引用。例如,它们可以是由GC控制的表中的不透明句柄

目前我只知道堆栈上dog的空间有其值0x00FFFFF,但我100%确定dog空间中的其他地方有其声明类型

我认为您指的是实例的实际运行时类型Dog。这是一个令人困惑的“声明”用法。实例未“声明”;实例被“分配”。变量是“声明的”,并且该变量具有声明的类型“Animal”

是的,在为“new Dog()”分配的实际实例数据中,有一个描述对象运行时类型的“令牌”。如果代币工作原理的确切细节对您很重要,请询问另一个问题

我想知道狗的堆栈空间的详细说明,目前我知道有一个引用地址,还有其他的吗

你的问题模棱两可,因为堆栈上有两个变量,它们都没有命名为“dog”

在运行时,堆栈空间只包含对为实例分配的堆空间的托管引用。C#编译器知道dog1的堆栈空间是编译时类型managed reference to Animal,dog2的堆栈空间是编译时类型managed reference to Dog。因此抖动也知道该信息。抖动在其自身的数据结构中保留关于抖动的信息;它不会污染烟囱。抖动可以保留这些信息用于优化或调试。或者,如果它不再需要这些信息,它可以把它扔掉


这又是一个实现细节;抖动完全可以随意在堆栈上添加任何附加信息。

您正确地推断了许多实现细节

在讨论这些细节之前,先介绍一些术语。有三种存储方式:

  • 非托管存储
  • 托管存储
  • 临时储存
非托管存储超出了您的问题范围。托管存储就是我们所说的“堆”。临时存储是“堆栈”或寄存器(如果抖动很巧妙且寄存器可用),但作为一个简化的假设,让我们忽略寄存器,只需将临时存储池称为“堆栈”

有四种类型:

  • 非托管指针
  • 值类型
  • 引用,又名,托管指针
  • 引用类型的实际实例
非托管指针超出了问题的范围。C#允许您直接操作引用(“托管指针”)和值类型;引用类型实例的内容仅通过引用进行操作,并且在CLR实现中始终位于堆上。(如果jitter有足够的智能知道对象不需要垃圾收集,并且无法在方法中生存,那么没有任何东西可以阻止它在堆栈上创建引用类型的实例,但实际上据我所知,我们的jitter不会这样做。)

其他三种东西可以在t上