分配给引用类型变量的指针/引用的隐藏值是多少?

问题描述 投票:3回答:1
int number = 1

number的值为1,因为它是值类型

分配给引用类型变量的指针的实际值是多少?

它是int还是字符串?还是有点位?如果你把它写出来会是什么样子?是否可以使用该值为变量分配引用?

Question harrysQuestion = new Question();

harrysQuestion只是新问题的指针或引用。那指针的价值是什么?如果我执行此操作,则分配给另一个Question变量的值相同:

Question harrysQuestionAgain = harrysQuestion;

这个数字是否指向我计算机内存中的某个位置?它是幕后的实际C#值变量吗?

c# value-type reference-type
1个回答
3
投票

这个数字是否指向我计算机内存中的某个位置?

从概念上讲,引用和指针是分开但相关的。实际上它们实际上是可以互换的,区别在于GC知道如何行走和修复引用(垃圾收集等),而不是指针(还有其他一些关于fixed如何在值的黑客方面起作用的事情,允许在堆栈上找到的参考值被解释为便宜地“固定”)。实际上,它们在所有实现中都非常接近(出于性能原因),您可以将它们视为有点相同。

您实际上想要获得引用的“值”(而不是取消引用它)是非常罕见的,除非您首先固定对象,否则您需要非常小心这样做,因为地址可以更改(并且指针版本不会被更正)。对于这个用例的需求实际上随着即将到来的“管道”工作而略有增加,因此Unsafe实用程序类型的corefxlab / myget版本实际上提供了一些方法来促进引用/指针的交换(包括内部指针/引用到对象中) ,但是:除非你做的事情很低,否则你可能永远不需要那样做。


每个请求(评论):我提到“固定”和“修复” - 这里的问题是.NET有一个“压缩”垃圾收集器,允许在运行时移动对象,只要它承诺修复所有引用并确保您从未在托管代码中注意到这一点。它没有承诺的是修复指针。所以:如果你要将任何对象看作指针,你需要告诉运行时(特别是:垃圾收集器)根本不要移动那个对象,或者至少在你告诉它你之前重做。这就是“钉扎”的含义。 “pin”有两种方法:

  • 对于长期引脚(通常像byte[]缓冲区,你将作为一个字段存储在一个对象中并传递给非托管代码作为指针),你可以对一个对象进行GCHandle,它会被记录在全局GC知道要看的结构
  • 对于堆栈上的引用的短期引脚,fixed关键字执行一些voodoo,让GC(总是查看每个堆栈)知道引用 - 因此引用的对象(该地址处的对象) - 应该被认为是固定的,而不需要不断地添加/删除到全局结构

作为一个可能有趣的旁注:“内部引用”和对值类型的引用是一个仅存在于堆栈中的概念 - 而不是作为最终可能在堆上的类型的字段(这意味着任何classstruct除了新的ref struct概念)。它们的工作方式与常规引用相同,但这些引用的目标是内容本身,而不是对象头的开头。这意味着

var fieldReference = ref this._someField;

要么

SomeOtherMethod(ref this._someField);

要么

SomeOtherMethod(ref someArray[index]);

只要内部引用只在堆栈上(即没有async / yield / capture-variables / etc),就可以在方法内部工作; GC很乐意完成解析对象内部指针的开销,但仅限于堆栈 - 以减少所涉及的工作的整体规模。

© www.soinside.com 2019 - 2024. All rights reserved.