谁是IDisposable的公共产权处置? [英] Who Disposes of an IDisposable public property?

查看:106
本文介绍了谁是IDisposable的公共产权处置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

If I have a SomeDisposableObject class which implements IDisposable:

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

和我有另一个类名为的aContainer ,其中有 SomeDisposableObject 作为公共财产的一个实例:

And I have another class called AContainer, which has an instance of SomeDisposableObject as a public property:

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 实例。

Which is fine, but I can't see how I can safely call m_someObject.Dispose() from AContainer.Dispose(), as another class may still have a reference to the m_someObject instance.

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

What is the best way to avoid this scenario?

(假设其他code依赖于 AContainer.SomeObject 总是有一个非空值,所以只需将创建实例之外的的aContainer 不是一个选项)

(Assume that other code relies on AContainer.SomeObject always having a non-null value, so simply moving the creation of the instance outside of the AContainer is not an option)

修改:我觉得有些评论者失踪的问题,我会用一些例子扩大。如果我只是实施的Dispose()方法对的aContainer 这就要求m_someObject.Dispose(),然后我留下了这些情况:

Edit: I'll expand with some example as I think some commenters are missing the issue. If I just implement a Dispose() method on AContainer which calls m_someObject.Dispose() then I am left with these situations:

// 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.

帮助吗?

推荐答案

没有单一的答案,它取决于你的情况下,关键的一点是由物业psented一次性资源再$ P $的所有权,如<一个href="http://stackoverflow.com/questions/674879/who-disposes-of-an-idisposable-public-property/674896#674896">Jon飞碟双向指出。

There is no single answer, it depends on your scenario, and the key point is ownership of the disposable resource represented by the property, as Jon Skeet points out.

这是有帮助的,有时来看看.NET Framework中的例子。这里有不同行为的三个例子:

It's sometimes helpful to look at examples from the .NET Framework. Here are three examples that behave differently:

  • 集装箱总部署。就是System.IO.StreamReader公开的一次性属性BaseStream。它被认为是对自己的基本流,处置的StreamReader始终部署基础流。

  • Container always disposes. System.IO.StreamReader exposes a disposable property BaseStream. It is considered to own the underlying stream, and disposing the StreamReader always disposes the underlying stream.

集装箱从未部署。 System.DirectoryServices.DirectoryEntry暴露了Parent属性。它不被视为拥有其母公司,这样处置的DirectoryEntry从来没有处置其母公司。

Container never disposes. System.DirectoryServices.DirectoryEntry exposes a Parent property. It is not considered to own its parent, so disposing the DirectoryEntry never disposes its parent.

在这种情况下,一个新的DirectoryEntry实例的parent属性提领,每次回来,并且主叫方为presumably预计处置它。可以说,这打破了性的指导方针,也许应该有一个的getParent()方法。

In this case a new DirectoryEntry instance is returned each time the Parent property is dereferenced, and the caller is presumably expected to dispose it. Arguably this breaks the guidelines for properties, and perhaps there should be a GetParent() method instead.

集装箱有时部署。 System.Data.SqlClient.SqlDataReader暴露一次性连接属性,但主叫方决定,如果读者拥有(因此部署)使用SqlCommand.ExecuteReader的的CommandBehavior论证的基础连接。

Container sometimes disposes. System.Data.SqlClient.SqlDataReader exposes a disposable Connection property, but the caller decides if the reader owns (and therefore disposes) the underlying connection using the CommandBehavior argument of SqlCommand.ExecuteReader.

另一个有趣的例子是System.DirectoryServices.DirectorySearcher,具有读/写支配财产SearchRoot。如果这个属性从外部设定,然后底层资源被假定不被拥有,因此不设置由容器。如果它不是从外部设定,基准由内部产生,和一个标志被设置,以确保它将被布置。你可以看到这一点卢茨反射。

Another interesting example is System.DirectoryServices.DirectorySearcher, which has a read/write disposable property SearchRoot. If this property is set from outside, then the underlying resource is assumed not to be owned, so isn't disposed by the container. If it's not set from outside, a reference is generated internally, and a flag is set to ensure it will be disposed. You can see this with Lutz Reflector.

您需要决定你的容器是否拥有资源,并确保您准确地记录其行为。

You need to decide whether or not your container owns the resource, and make sure you document its behavior accurately.

如果你决定你自己的资源,并且属性为读/写,你需要确保你的二传手处置任何引用它的替换,如:

If you do decide you own the resource, and the property is read/write, you need to make sure your setter disposes any reference it's replacing, e.g.:

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;

更新:我已经更新上面的例子中考虑到这(使用的ReferenceEquals而:格雷厄姆正确地指出的评论认为,这是更好地测试m_someObject =处置前的二传手价值不是!=要明确)。虽然在许多真实世界情景设定器的存在可能意味着该对象不是由容器所拥有的,因此将不被设置。

UPDATE: GrahamS rightly points out in comments that it's better to test for m_someObject != value in the setter before disposing: I've updated the above example to take account of this (using ReferenceEquals rather than != to be explicit). Although in many real-world scenarios the existence of a setter might imply that the object is not owned by the container, and therefore won't be disposed.

这篇关于谁是IDisposable的公共产权处置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆