Reputation: 6884
Copies of some data doesn't belong on the heap (without special treatment.) For example, the JavaScriptValue struct on the stack, does a great job in interop with the Chakra JavaScript engine.
But as I understand it, storing such a value on the managed heap, (without proper reference counting) results in a possible dangling reference. Is there a way to declare a c# structure like this as non-boxable?
Clarification, I want the c# compiler to generate an error message if any boxing operations are generated on the type.
Reference: See MSDN JSAddRef reference which says:
This only needs to be called on JsRef handles that are not going to be stored somewhere on the stack. Calling JsAddRef ensures that the object the JsRef refers > to will not be freed until JsRelease is called.
I gather from this that Chakra may be using a "conservative garbage collection" approach, making JsAddRef/JsRelease unnecessary for stack based JsRef handles. I would want to use to use a class (not structure) to wrap JsRef handles on the heap, and have a conversion operation to call JsAddRef, and use the IDisposable pattern to call JsRelease.
Upvotes: 0
Views: 297
Reputation: 764
With C# 7.2+, the answer is yes: just use the ref keyword on your struct ref struct
. It will be allowed only on the stack, not on the heap (and hence no boxing can be done on it).
See here for more information: http://www.devsanon.com/c/c-7-2-introducing-ref-struct/
And here: https://learn.microsoft.com/en-us/dotnet/csharp/write-safe-efficient-code#use-ref-struct-types
Upvotes: 2
Reputation: 5515
As other's have written, value types will be boxed (you can think of it like they're being wrapped in a reference type) to be able to go on the heap.
But more important, this has nothing to do with dangling references and reference counting. Doesn't matter where it's stored.
What I believe you're asking is how to manage native resources, and that's another matter. If you allocate a resource from something outside the .NET world, you generally need to make sure you release/free it when you're done with it. Normally you wrap it up in a class that implements IDisposable
and dispose of it manually (or in a destructor). Now, if you forget to dispose something you should, or keep a reference to something already disposed, you can get into trouble. But all this depends on what the resource is.
For your specific case with JavaScriptValue
, I don't really know how that works. Though it looks to me that if the IntPtr in there referred to something that needs to be disposed, JavaScriptValue
would have been a class implementing IDisposable and not a struct. Storing something that needs to be disposed in a struct would be a very good way of getting into trouble, since you could potentially have copies of that reference all over the place. So I would assume that you don't need to bother - but you should check the docs to be sure.
Upvotes: 0
Reputation: 4836
it gets boxed because you store it in a datastructure that goes on the heap.
you put it there by wrapping it in a non value type.
There are lots of questions around this subject. If you dont want to read a book then you should read all of these. Some of them are v interesting.
So no its not possible to create a non boxable struct - it gets boxed because of what you do.
Upvotes: 0
Reputation: 40838
The CLI ECMA-335 specification says (section I.8.2.4):
All value types have an operation called
box
. Boxing a value of any value type produces its boxed value; i.e., a value of the corresponding boxed type containing a bitwise copy of the original value.
There is some additional language saying what happens with Nullable<T>
(the contained value is boxed or a null reference is produced) and that the box operation cannot be performed on managed pointers, but there is no mention of any exception for value types.
Upvotes: 0