在不可变对象中处理终结器中的底层对象

时间:2012-07-04 02:58:41

标签: c# .net design-patterns awesomium

我正在尝试回绕Awesomium并使其看起来尽可能接近我的代码WebBrowser,因为这是针对已经使用{{1}的现有应用程序}}。

在这个库中,有一个名为WebBrowser的类,它代表一个javascript对象。例如,您可以通过调用JSObject类的ExecuteJavascriptWithResult方法来获取其中一个。如果您将其称为WebView,那么您将获得代表该文档的myWebView.ExecuteJavascriptWithResult("document", string.Empty).ToObject()

我正在编写一个名为JSObject的不可变类(它的唯一字段是readonly JSObject对象),它包含JSObjectWrap,我希望将其用作其他类的基类。模拟.NET类,例如JSObjectHtmlElement。现在,这些类不实现HtmlDocument,但Dispose实现。我首先想到的是在JSObject的终结器中调用基础JSObject的{​​{1}}方法(而不是让Dispose实现JSObjectWrap),这样才能我的其余代码可以保持原样(不必在任何地方添加JSObjectWrap,并确保每个Dispose都得到妥善处理。

但我刚刚意识到,如果两个以上的using具有相同的基础JSObjectWrap并且其中一个被最终确定,那么这将使另一个JSObjectWrap陷入困境。所以现在我想也许我应该保持JSObject JSObjectWrap的静态Dictionary,并且计算JSObjects引用它们的数量,但这听起来很混乱,我认为可能会导致重大性能问题。

因为这听起来像一个普通的模式,我想知道是否有其他人有更好的主意。

2 个答案:

答案 0 :(得分:1)

如果超过2个JSObjectWrap具有相同的底层JSObject,则有超过2个引用引用JSObject,因此在引用计数达到0之前它不会被垃圾收集。我错过了什么?

评论后编辑:

确定。我知道了。你想要做的是能够共享JSObject但是只要有人引用它就不想处理它。对我来说,唯一的出路似乎就是你建议保留JSObjects的字典。要绘制并行,这与.NET / JVM将为不可变的字符串做的非常类似,只有在我们的示例中的dispose意味着在这里对String进行垃圾收集并且除非引用计数为零(我是除非维护字典,否则无法确定猜测,字符串不符合垃圾收集的条件。

答案 1 :(得分:1)

要跟进user1168577的回答,您当然可以设置系统,以便在包装器和包装之间建立一对一的关系。然后(更喜欢组合而不是继承),让库类在适当的时候保存对同一个包装类的引用。然后垃圾收集器可以发挥它的魔力。

但这样做可能会浪费你的时间。 IDisposable实现者的标准模式在终结器中调用Dispose,如果之前没有调用过的话。用ILSpy或类似程序反编译JSObject以确认它是这样做的。如果确实如此,则无需编写的代码!

如果您确定您的包装库永远不会用于新代码,那么您甚至不需要实现IDisposable;如果是,则实现接口,但允许遗留代码省略调用Dispose,除非你因为原因需要修改它。