Shmoopy
Shmoopy

Reputation: 5534

When calling GCHandle.Alloc on a class, will it also pin members of that class?

Suppose I have a class that has a few references to other classes:

class Bar {

}

class Baz {

}

class Foo {
    Bar bar;
    Baz baz;
}

Then I'm calling GCHandle.Alloc on an instance of that class:

var foo = new Foo() { bar = new Bar(), baz = new Baz() };
var handle = GCHandle.Alloc(foo, GCHandleType.Normal);

Then I'm passing the handle to native code which passes it back to C# in a callback function. C# code will access both bar and baz members. Will pinning foo also guarantee that bar and baz are also pinned or should I pin them explicitly?

Follow up question assuming that I need to pin bar and baz explicitly:

Suppose I'd like to pin an object which I'm not the author of its class (also assume that the object has a few private members). How can I pin that object so it remains in usable (meaning, non of its members were collected by the GC)

Upvotes: 1

Views: 419

Answers (1)

Evk
Evk

Reputation: 101533

Note that you are not pinning foo. To pin it you'd have to use GCHandleType.Pinned. This would prevent GC to move the pinned object in memory and will allow to reach object directly using a handle (so handle will basically represent pointer to that object in memory). But it's not necessary in this case because native code does not use the handle - it passes it back to managed code. So you correctly using Normal handle (which again does not pin the object). Also as correctly mentioned in comments - you won't be able to pin foo anyway, because only objects with only blittable members can be pinned.

So only thing this Normal handle does is it prevents object from garbage collection, and allows you to refer to this object inderectly using handle from managed code (in this case from your callback function). So handle itself is not a pointer to managed object, but can be used to reach that object from managed code (using handle.Target).

As such, because Foo cannot be collected, then bar and baz cannot be collected either, so you don't need to do anything about them.

Upvotes: 1

Related Questions