如何正确设计具有一次性对象内部引用的对象

本文关键字:对象 内部 引用 一次性 何正确 | 更新日期: 2023-09-27 18:28:11

假设,我有以下类:

public class DisposableObj : IDisposable
{
    public ChildObj CreateObj();
    internal object GetSomething();
    // ...
}
public class ChildObj
{
    private DisposableObj m_provider;
    public void DoSomething()
    {
        m_provider.GetSomething();
    }
    // ...
}

有可能在某个时刻,一次性对象会被丢弃,但子对象仍然有对它的引用

若此时用户将调用DoSomething方法,则子对象将尝试访问已处理的对象。这是不好的,因此问题:

我应该如何正确地设计这样的类?

更新/澄清:

我知道ObjectDisposedException等等。我的问题听起来可能应该是:如何正确地通知用户异常情况,以及如何设计类以使维护它们更容易?

如何正确设计具有一次性对象内部引用的对象

虽然这在技术上是可能的,但在您的程序中,这应该是一种异常状态-我无法想象您为什么会故意设置这种情况。

话虽如此,这在设计中明确了谁负责处理DisposableObj,以及何时-如果任何子对象随后访问了已处理的对象,您可以争辩说这应该导致异常-不要绕过这个问题,而是抛出一个异常,让异常冒出,这样您就可以在发现问题时修复逻辑。

在实现方面,您可以通过保持一个布尔值来实现这一点,该布尔值跟踪DisposableObj是否被释放,并且在以后的访问中只抛出ObjectDisposedException。为了澄清,我的意思是DisposableObj对象本身应该跟踪它的状态,并在它被处理后在它的任何方法调用上抛出ObjectDisposedException

首先想到的是:
为ChildObj类提供一个名为ProviderDisposed的内部布尔属性
在DisposableObj 中从Dispose将此属性设置为true

但是,您应该保留一个创建的对象列表,以便与每个对象通信—主对象的已处理状态。

List<ChildObj> childsCreated = new List<ChildObj>();
public ChildObj CreateObj()
{
    ChildObj obj = new ChildObj();
    childsCreated.Add(obj);
    return obj;
}
public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
    // Check to see if Dispose has already been called.
    if(!this.disposed)
    {
        if(disposing)
        {
            foreach(ChildObj obj in childsCreated)
                obj.ProviderDisposed = true;
            childsCreated = null;
        }
        disposed = true;
    }
}
public class ChildObj   
{   
    private DisposableObj m_provider;   
    private bool m_providerDisposed = false;
    public bool ProviderDisposed 
    { set { m_providerDisposed = true; } }
    public void DoSomething()   
    {   
        if(m_providerDisposed == false)
             m_provider.GetSomething();
        // else // as from **@BrokenGlass answer**
        //     throw new ObjectDisposedException();   
    }   
    // ...   
}