Burt_Harris
Burt_Harris

Reputation: 6884

Is it possible to create a non-boxable struct in C#

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

Answers (4)

Spi
Spi

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

Chris
Chris

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

John Nicholas
John Nicholas

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

Mike Zboray
Mike Zboray

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

Related Questions