2010-07-22 58 views
1

我有这个类:在这种情况下,Dispose()会提前释放资源吗?

class Foo : IDisposable 
{ 
    SomeBigResource resource; 

    void UsingResource() 
    { 
    using(Bar bar = new Bar(SomeBigResource) 
     bar.doStuff(); 
    } 

    void Dispose() 
    { 
    resource.Dispose(); 
    } 
} 

void Function() 
{ 
    using (Foo foo = new Foo(new SomeBigResource)) 
    foo.UsingResource(); 
} 

酒吧对象具有完全相同的Dispose()功能。
我的SomeBigResource会被释放还是GC智能足以在第二次使用完成后再释放它?

+4

Dispose与GC无关。 – 2010-07-22 14:12:15

+0

SomeBigResource所属的类必须配置它 – Arseny 2010-07-22 14:19:30

回答

4

如果Dispose方法无论是在FooBar电话DisposeSomeBigResource对象上,该方法将被调用两次。如果方法正确实施,它将首次释放资源,第二次不做任何事情。

你有什么是责任混淆,两个对象负责在SomeBigResource对象上调用Dispose。这是你想避免的,因为一个对象不知道另一个对象是否仍然需要这个资源,所以你只想把责任放在一个地方。

您应该使Foo对象负责资源的生命周期,或者完全在对象之外处理它。后者更有意义,因为这是您创建实例的地方:

using (SomeBigResource resource = new SomeBigResource()) { 
    using (Foo foo = new Foo(resource)) { 
    foo.UsingResource(); 
    } 
} 
2

您的资源将被丢弃两次。

GC完全不知道IDisposable s和using声明。

将每个using声明翻译成try/finally块,并在finally块中调用Dispose()
这是一个常规的方法调用,它将始终执行。

因此,在UsingResource()using语句将配置资源,然后在Function()using声明再次将其丢弃。

全部IDisposable实现应该是幂等的(第二次调用应该没有危害)。因此,(假设SomeBigResource正确地实现了IDisposable),你的代码应该可以正常工作。

但请注意,在您的班级中,一个空的using区块会抛出NullReferenceException,这是非常错误的。
您应该在Dispose方法中添加一个null支票。

+0

所以基本上我应该删除UsingResource()中的使用? – 2010-07-22 14:14:58

+0

实际上,您应该删除该字段并将其设为私有变量。 – SLaks 2010-07-22 14:16:46

+1

@the_drow,我会围绕'SomeBigResource'实例包装'using',而不是依赖于那个实例的对象。如果他们没有创建它,'Foo'和'Bar'不应该负责清理'SomeBigResource'。 – 2010-07-22 14:17:27

2

这取决于执行Bar.Dispose()。假设它具有与Foo类似的实现方式,那么,是的,发布会提前发生。

看看Dispose pattern guidancethis SO question。你可能会想到更多的角落案例。

2

我想这行应为:

using(Bar bar = new Bar(resource)) 

如果在bar布置是这样的话,那么,它应该处置resource

所以,是的。当bar配置在UsingResource中时,它将配置resource,这样如果您稍后尝试使用它,则应该会抛出ObjectDisposedException。 (虽然你简单的例子,这是不应该的。)