复杂的对象图中的终身发行了可置的无管理资源?
-
02-10-2019 - |
题
这个问题是关于处理不管理的资源(COM Interop),并确保不会出现任何资源泄漏。我会感谢我似乎以正确的方式做事的反馈。
背景:
假设我有两个课:
一类
LimitedComResource
这是围绕com对象的包装器(通过某些API接收)。这些com对象只能有限,因此我的班级实现了IDisposable
接口将在不再需要时释放com对象。另一种类型的对象
ManagedObject
暂时创建以在LimitedComResource
. 。他们不是IDisposable
.
为了在图中总结以上的内容,我的课程可能看起来像这样:
+---------------+ +--------------------+
| ManagedObject | <>------> | LimitedComResource |
+---------------+ +--------------------+
|
o IDisposable
(我将在短短的时间内为这两个类提供示例代码。)
问题:
自从我的临时 ManagedObject
物体无法一次性,我显然无法控制它们将要多久。但是,与此同时,我可能有 Dispose
D LimitedComObject
那 ManagedObject
指的是。 我如何确保 ManagedObject
无法访问 LimitedComResource
那不再在那里吗?
+---------------+ +--------------------+
| managedObject | <>------> | (dead object) |
+---------------+ +--------------------+
我目前已经用弱参考和一个标志在 LimitedResource
这标志着是否已经处置了一个物体。 有更好的方法吗?
示例代码(我目前得到的):
LimitedComResource
:
class LimitedComResource : IDisposable
{
private readonly IUnknown comObject; // <-- set in constructor
...
void Dispose(bool notFromFinalizer)
{
if (!this.isDisposed)
{
Marshal.FinalReleaseComObject(comObject);
}
this.isDisposed = true;
}
internal bool isDisposed = false;
}
ManagedObject
:
class ManagedObject
{
private readonly WeakReference limitedComResource; // <-- set in constructor
...
public void DoSomeWork()
{
if (!limitedComResource.IsAlive())
{
throw new ObjectDisposedException();
// ^^^^^^^^^^^^^^^^^^^^^^^
// is there a more suitable exception class?
}
var ur = (LimitedComResource)limitedComResource.Target;
if (ur.isDisposed)
{
throw new ObjectDisposedException();
}
... // <-- do something sensible here!
}
}
解决方案
不,这不行。弱者只会告诉您,托管对象收集了垃圾。这与Idisposable无关。处置点()是释放非管理资源 前 垃圾收集器做到了。
实际上,如果托管对象位于Gen#1中,并且COM包装器位于Gen#0中,那么您会遇到一个严重的问题。虚弱的报道无法保持包装器的活力,它将被收集,并且在您有机会自己调用Dispose()之前就处置了COM对象。
只需在托管对象中存储对包装对象的简单引用即可。您可以在调用Dispose()后将其设置为null,以便包装器可以收集。如果客户端代码试图使用它并且引用为null,则抛出objectDisposedException。或重新创建它,如果有道理。
其他提示
当您将弱参考对象类型的弱参考的目标施放时,如果对象被处置,它将返回null。只需检查您在执行操作之前,您获得的值是否为null。在 文档. 。您可能还会找到本文 使用弱参考 使用。这是后一篇文章的相关报价:
要建立强有力的参考并再次使用对象,请将弱率的目标属性投放给对象的类型。如果目标属性返回null,则收集对象;否则,您可以继续使用该对象,因为该应用程序已经重新获得了对其的强烈参考。
例子:
class ManagedObject
{
private readonly WeakReference limitedComResource; // <-- set in constructor
...
public void DoSomeWork()
{
var ur = (LimitedComResource)limitedComResource.Target;
if (ur == null)
{
throw new ObjectDisposedException();
}
... // <-- do something sensible here!
}
}