Disposing underlying object from finalizer in an immutable object
-
19-06-2021 - |
Question
I'm trying to wrap around Awesomium
and make it look to the rest of my code as close as possible to NET's WebBrowser
since this is for an existing application that already uses the WebBrowser
.
In this library, there is a class called JSObject
which represents a javascript object. You can get one of this, for instance, by calling the ExecuteJavascriptWithResult
method of the WebView
class. If you'd call it like myWebView.ExecuteJavascriptWithResult("document", string.Empty).ToObject()
, then you'd get a JSObject
that represents the document.
I'm writing an immutable class (it's only field is a readonly JSObject
object) called JSObjectWrap
that wraps around JSObject
which I want to use as base class for other classes that would emulate .NET classes such as HtmlElement
and HtmlDocument
. Now, these classes don't implement Dispose
, but JSObject
does. What I first thought was to call the underlying JSObject
's Dispose
method in my JSObjectWrap
's finalizer (instead of having JSObjectWrap
implement Dispose
) so that the rest of my code can stay the way it is (instead of having to add using
's everywhere and make sure every JSObjectWrap
is being properly disposed).
But I just realized if more than two JSObjectWrap
's have the same underlying JSObject
and one of them gets finalized this will mess up the other JSObjectWrap
. So now I'm thinking maybe I should keep a static Dictionary
of JSObjects
and keep count of how many of each of them are being referenced by a JSObjectWrap
but this sounds messy and I think could cause major performance issues.
Since this sounds to me like a common pattern I wonder if anyone else has a better idea.
Solution
To follow up on user1168577's answer, you could of course set the system up so there's a one to one relationship between wrappers and wrappees. Then (preferring composition over inheritance), have the library classes hold a reference to the same wrapper class, where appropriate. Then the garbage collector can do its magic.
But doing that its probably wasting your time. The standard pattern for IDisposable implementers calls Dispose in the finalizer, if it hadn't been called before. Decompile JSObject with ILSpy or similar to confirm that it does this. If it does, then there's no need for you to write code that also does that!
If you are sure your wrapper library will never be used for new code, then you don't even need to implement IDisposable; if it will be, then implement the interface, but allow the legacy code to omit calling Dispose unless you have to modify it for reasons.
OTHER TIPS
If more than 2 JSObjectWrap have the same underlying JSObject, there are more than 2 references referencing JSObject, so it won't be garbage collected until the reference count reaches 0. Am I missing something?
Edit after comment:
Ok. I get it. What you want to do is to be able to share JSObject but want to not dispose it as long as someone's referencing it. To me the only way out seems to be what you have suggested by keeping a dictionary of JSObjects. To draw a parallel, this is very similar to what .NET/JVM would do for immutable Strings that are shared with the only difference being that dispose in our example means garbage collection of a String here and unless the reference count is zero (which I guess cannot be determined unless a dictionary is maintained), a String is not eligible for garbage collection.