这个问题是关于处理不管理的资源(COM Interop),并确保不会出现任何资源泄漏。我会感谢我似乎以正确的方式做事的反馈。

背景:


假设我有两个课:

  • 一类 LimitedComResource 这是围绕com对象的包装器(通过某些API接收)。这些com对象只能有限,因此我的班级实现了 IDisposable 接口将在不再需要时释放com对象。

  • 另一种类型的对象 ManagedObject 暂时创建以在 LimitedComResource. 。他们不是 IDisposable.

为了在图中总结以上的内容,我的课程可能看起来像这样:

            +---------------+           +--------------------+
            | ManagedObject | <>------> | LimitedComResource |
            +---------------+           +--------------------+
                                                  |
                                                  o IDisposable

(我将在短短的时间内为这两个类提供示例代码。)

问题:


自从我的临时 ManagedObject 物体无法一次性,我显然无法控制它们将要多久。但是,与此同时,我可能有 DisposeD LimitedComObjectManagedObject 指的是。 我如何确保 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! 
    } 
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top