0

一些数据的副本不属于堆(没有特殊处理)。例如,堆栈上的JavaScriptValue结构在与 Chakra JavaScript 引擎的互操作方面做得很好。

但据我了解,将这样的值存储在托管堆上(没有正确的引用计数)会导致可能的悬空引用。有没有办法将这样的 ac# 结构声明为不可装箱

澄清,如果在类型上生成任何装箱操作,我希望 c# 编译器生成错误消息。

参考:请参阅MSDN JSAddRef 参考,其中说:

这只需要在不会存储在堆栈中某处的 JsRef 句柄上调用。调用 JsAddRef 确保 JsRef 所引用的对象在调用 JsRelease 之前不会被释放。

我从中得知,Chakra 可能正在使用“保守的垃圾收集”方法,使得基于堆栈的 JsRef 句柄不需要 JsAddRef/JsRelease。 我想使用一个类(而不是结构)来包装堆上的 JsRef 句柄,并有一个转换操作来调用 JsAddRef,并使用 IDisposable 模式来调用 JsRelease。

4

4 回答 4

1

对于 C# 7.2+,答案是肯定的:只需在 struct 上使用ref关键字ref struct。它只允许在堆栈上,而不是在堆上(因此不能对其进行装箱)。

有关更多信息,请参见此处:http: //www.devsanon.com/c/c-7-2-introducing-ref-struct/

在这里: https ://docs.microsoft.com/en-us/dotnet/csharp/write-safe-efficient-code#use-ref-struct-types

于 2021-07-18T13:14:19.987 回答
0

它被装箱了,因为您将它存储在堆上的数据结构中。

把它包装在一个非值类型中。

关于这个主题有很多问题。如果你不想读一本书,那么你应该阅读所有这些。其中一些很有趣。

所以不,它不可能创建一个不可装箱的结构——它会因为你所做的而被装箱。

于 2014-07-13T08:29:35.727 回答
0

CLI ECMA-335 规范说(第I.8.2.4 节):

所有值类型都有一个称为 的操作box。对任何值类型的值进行装箱会产生其装箱值;即,包含原始值的按位副本的相应装箱类型的值。

还有一些额外的语言说明会发生什么Nullable<T>(包含的值被装箱或产生空引用)并且不能对托管指针执行装箱操作,但没有提及值类型的任何异常。

于 2014-07-13T08:34:03.240 回答
0

正如其他人所写的那样,值类型将被装箱(您可以将其想象为它们被包装在引用类型中)以便能够进入堆。

但更重要的是,这与悬空引用和引用计数无关。不管它存储在哪里。

我相信您要问的是如何管理原生资源,这是另一回事。如果您从 .NET 世界之外的资源分配资源,通常需要确保在完成后释放/释放它。通常,您将其包装在一个类中,该类IDisposable手动实现和处理它(或在析构函数中)。现在,如果你忘记处理你应该处理的东西,或者保留对已经处理的东西的引用,你可能会遇到麻烦。但这一切都取决于资源是什么。

对于您的具体情况JavaScriptValue,我真的不知道它是如何工作的。尽管在我看来,如果那里的 IntPtr 提到了需要处理的东西,那JavaScriptValue将是实现 IDisposable 的类而不是结构。将需要处理的内容存储在结构中将是陷入麻烦的一种很好的方法,因为您可能会在整个地方拥有该引用的副本。所以我假设你不需要打扰 - 但你应该检查文档以确定。

于 2014-07-13T09:05:00.513 回答