避免显式调用Dispose()合理吗

本文关键字:Dispose 调用 | 更新日期: 2023-09-27 18:20:41

制定一条规则来反对在IDisposable对象上显式调用Dispose()合理吗?

是否存在using语句无法正确确保IDisposable对象被清理的情况?

避免显式调用Dispose()合理吗

制定一条规则禁止在IDisposable对象上显式调用Dispose()是否合理?

没有。

是否存在using语句无法正确确保IDisposable对象被清理的情况?

当然,在某些情况下,使用using为您处理对象是没有意义的。例如,对象的期望寿命不受包含using语句的方法的特定激活的约束的所有情况。

例如,考虑一个"接管"另一个一次性对象的一次性对象。"外部"对象很可能由using块处理,但是,如果不显式调用Dispose(),如何处理可能存储在外部对象的私有字段中的"内部"对象?

在某些情况下,根本无法避免对Dispose的显式调用并保持正确的语义。例如,考虑具有同样类型为IDisposable的字段的IDisposable对象。他们必须明确调用Dispose来处理字段

class Container : IDisposable {
  private readonly IDisposable _field;
  public void Dipose() {
    // Don't want a using here.
    _field.Dispose();
  }
}

一个自然的假设是,您总是可以在对象上调用Dispose,这将清理对象的资源,而不管对象处于什么状态。

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

WCF客户端代理就是一个例子。。

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

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的一揽子规则。

using语句(实际上是try/finaly的简写,在finally块中调用Dispose)适用于获取资源、使用资源,然后在同一方法中处理资源的场景。如果您对资源没有这样的线性使用(例如,它的使用在方法之间划分),您将不得不调用Dispose

如果创建一次性类型的实例的成本很高(例如,封装远程连接的类型),则可能需要重用实例来分摊成本。在这种情况下,using将不起作用,您将不得不在某个时候调用Dispose

我会投票反对这样的规则,如果你有一个对象要在几个函数调用中多次使用,using语句会强制处理该对象,下次你想使用它时,你必须重新初始化。。。