当前位置:  开发笔记 > 编程语言 > 正文

谁处置了IDisposable公共财产?

如何解决《谁处置了IDisposable公共财产?》经验,为你挑选了3个好方法。

如果我有一个SomeDisposableObject实现的类IDisposable:

class SomeDisposableObject : IDisposable
{
    public void Dispose()
    {
        // Do some important disposal work.
    }
}

我有另一个叫做的类AContainer,它有SomeDisposableObject一个公共属性的实例:

class AContainer
{
    SomeDisposableObject m_someObject = new SomeDisposableObject();

    public SomeDisposableObject SomeObject
    {
        get { return m_someObject; }
        set { m_someObject = value; }
    }
}

然后FxCop将坚持AContainer也是IDisposable.

这是很好的,但我看不出我可以安全地调用m_someObject.Dispose()AContainer.Dispose(),作为另一个类可能还是要在一个参考m_someObject实例.

避免这种情况的最佳方法是什么?

(假设其他代码依赖于AContainer.SomeObject始终具有非空值,因此只是将实例的创建移到外部AContainer不是一个选项)

编辑:我将扩展一些例子,因为我认为一些评论者错过了这个问题.如果我只实现一个调用m_someObject.Dispose()的Dispose()方法,AContainer那么我将留下这些情况:

// Example One
AContainer container1 = new AContainer();
SomeDisposableObject obj1 = container1.SomeObject;
container1.Dispose();
obj1.DoSomething(); // BAD because obj1 has been disposed by container1.

// Example Two
AContainer container2 = new AContainer();
SomeObject obj2 = new SomeObject();
container2.SomeObject = obj2; // BAD because the previous value of SomeObject not disposed.
container2.Dispose();
obj2.DoSomething(); // BAD because obj2 has been disposed by container2, which doesn't really "own" it anyway.  

这有帮助吗?



1> Joe..:

没有一个答案,这取决于你的情况,关键点是财产所代表的可支配资源的所有权,正如Jon Skeet指出的那样.

查看.NET Framework中的示例有时很有帮助.以下是三个表现不同的示例:

容器总是处置.System.IO.StreamReader公开一次性属性BaseStream.它被认为拥有底层流,并且处理StreamReader始终处理底层流.

容器永远不会丢弃.System.DirectoryServices.DirectoryEntry公开Parent属性.它不被认为拥有其父级,因此处理DirectoryEntry永远不会释放其父级.

在这种情况下,每次取消引用Parent属性时都会返回一个新的DirectoryEntry实例,并且可能需要调用者处理它.可以说这打破了属性的准则,也许应该有一个GetParent()方法.

容器有时处理.System.Data.SqlClient.SqlDataReader公开一次性Connection属性,但调用者使用SqlCommand.ExecuteReader的CommandBehavior参数决定读者是否拥有(并因此处置)底层连接.

另一个有趣的例子是System.DirectoryServices.DirectorySearcher,它具有读/写一次性属性SearchRoot.如果从外部设置此属性,则假定基础资源不属于该属性,因此容器不会处置该属性.如果它不是从外部设置的,则在内部生成引用,并设置一个标志以确保它将被丢弃.你可以用Lutz Reflector看到这个.

您需要确定容器是否拥有该资源,并确保准确记录其行为.

如果您确定拥有该资源,并且该属性是可读/写的,则需要确保您的setter处理它正在替换的任何引用,例如:

public SomeDisposableObject SomeObject    
{        
    get { return m_someObject; }        
    set 
    { 
        if ((m_someObject != null) && 
            (!object.ReferenceEquals(m_someObject, value))
        {
            m_someObject.Dispose();
        }
        m_someObject = value; 
    }    
}
private SomeDisposableObject m_someObject;

更新:GrahamS在评论中正确地指出在处置之前最好在setter中测试m_someObject!= value:我已经更新了上面的例子以考虑到这一点(使用ReferenceEquals而不是!=显式).虽然在许多现实场景中,setter的存在可能意味着该对象不归容器所有,因此不会被处置.



2> Jon Skeet..:

这实际上取决于谁在理论上"拥有"一次性物品.在某些情况下,您可能希望能够传入对象,例如在构造函数中,而不会让您的类负责清理它.其他时候你可能想要自己清理它.如果您正在创建对象(如示例代码中所示),那么清理它几乎肯定是您的责任.

至于财产 - 我不认为拥有财产应该真正转移所有权或类似的东西.如果您的类型负责处理对象,则应该保留该责任.



3> Igor Zelaya..:

真正的问题可能是您的面向对象设计.如果AContainer是Disposed,则也应该处理其所有成员对象.如果不是这听起来像你可以处置一个身体但想要保持腿部实例生活.听起来不对劲.

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有