2012-01-16 33 views
9

IDisposable对象明确调用Dispose()是否合理?避免显式调用Dispose()是否合理?

是否有任何情况下,using声明无法正确确保IDisposable对象被清理?

+0

尽管我喜欢让垃圾收集器为我管理我的记忆,但如果我有任何理由这样做,对于调用Dispose()我毫无保留。 – 2012-01-16 23:08:24

+4

@SamIam:调用Dispose的要点是释放内存管理器*不为您提供的资源*。 Dispose是明确的关于管理*非内存*资源,所以不要把内存管理器放进去。 – 2012-01-16 23:15:48

回答

11

IDisposable对象明确调用Dispose()是否合理?

是否有其中using语句不能正确确保IDisposable对象清理任何情况下?

当然,还有它是没有意义的使用using处置对象为您的案件。例如,对象的所需生命周期不受包含using语句的方法的特定激活约束的所有情况。

考虑例如“接管”另一个一次性物品的一次性物品。 “外部”对象很可能被using块处置,但是如何处理可能存储在外部对象的专用字段中的“内部”对象,而不需要明确地调用Dispose()

+0

一个很好的,干净的答案!我想这个问题从我对C++的退休爱好以及它用于表达RAII的干净语法中冒出来。 – 2012-01-17 00:17:16

+1

@NickStrupat:通过“干净的语法”你的意思是“该字符'}'导致代码执行”。这不是一个“干净”的语法,这是一个危险的误导性语法。划分词法范围的字符不应与*可执行代码*相关联;它在C++中的事实是C++的设计缺陷之一。对我而言,这仍然是一个谜,为什么有人认为这是一个好主意;如果我的资源清理代码很重要,那么我希望它在代码中显式*,以便我可以*读*,*理解*和*调试*它。如果它很重要,不要隐藏它。 – 2012-01-17 00:23:48

+1

@EricLippert - 为了扮演魔鬼的拥护者,在C#中关闭'using'块的'}'可以引起代码执行。你觉得这是“危险的误导”的语法,还是在区块开始时出现的“使用”足以免除它? – kvb 2012-01-17 12:34:17

5

在某些情况下,根本不可能避免显式调用Dispose并仍保持适当的语义。例如,考虑具有IDisposable类型字段的IDisposable对象。他们必须我们Dispose显式调用处置场

class Container : IDisposable { 
    private readonly IDisposable _field; 

    public void Dipose() { 

    // Don't want a using here. 
    _field.Dispose(); 
    } 
} 
+1

好吧,你仍然可以使用一个使用块来触发处理...但是它会很奇怪,因为它不会匹配对象的整个生命周期,只是它的死亡。 'using'控件表达式不必创建对象,只需分配一个变量即可。 – 2012-01-16 23:06:12

+0

@BenVoigt是你*可以*使用使用。这将是一个有点矫枉过正; 0 – JaredPar 2012-01-16 23:06:58

1

如果一次性类型的创建实例的成本高(例如它封装了一个远程连接的类型),您可能希望重新使用实例摊销成本。在这种情况下,using将不会有用,您必须在某个时间呼叫Dispose

1

我会投票反对这样的规则,如果你有一个对象你想多次使用多个函数调用,使用声明将强制处理该对象,下一次你想使用它,你有重新初始化...

2

一个using声明(这确实是简写一个try /终于与Dispose称为finally块)可以在您获取资源,利用它,那么同一个方法内处理它的场景。如果您没有这种资源的线性使用情况(例如,它的使用情况在方法中分开),您必须致电Dispose

3

一个很自然的假设是,你可以随时拨打Dispose的对象,而这将清理对象的资源,不管对象是什么状态。

这种自然的假设并不总是正确的假设。

一个例子是WCF client proxies.

管理代理一生的正确方法如下:

var serviceClient = new sandbox.SandboxServiceClient(); 
serviceClient.HelloWorld(name); 
if(serviceClient.State == CommunicationState.Faulted) 
{ 
    serviceClient.Abort(); 
} 
else 
{ 
    serviceClient.Dispose(); 
} 

切换到using语法将导致不安全的代码:

using (var serviceClient = new sandbox.SandboxServiceClient()) 
{ 
    serviceClient.HelloWorld(name); 
} // Here An exception will be thrown if the channel has faulted 

你可以说(大家都做 )这是WCF的一个有缺陷的设计方面,但编程的实际情况是我们有时必须修改我们的风格以适应我们使用的框架。下面是一个示例,其中对明确的Dispose的一揽子规则不适用,即使对象的生命周期包含在一个函数调用中。

相关问题