代码之家  ›  专栏  ›  技术社区  ›  fletcher

决不能使用using语句和IDisposable的场合

  •  8
  • fletcher  · 技术社区  · 14 年前

    我在读关于 this scenario 使用C#using语句可能会导致问题。如果using语句末尾调用的Dispose函数也要抛出异常,则using块范围内抛出的异常可能会丢失。这强调了在决定是否添加using语句时,在某些情况下应该小心。

    这是IDisposable接口的另一个用法,用于创建性能计时器,该计时器将停止计时器并将时间记录到Dispose函数中的注册表中。 http://thebuildingcoder.typepad.com/blog/2010/03/performance-profiling.html

    这是IDisposable接口的好用法吗?它不会清理资源或处理任何其他对象。但是,我可以看到它如何通过将正在分析的代码整齐地包装在using语句中来清理调用代码。

    有没有过不应该使用using语句和IDisposable接口的时候?以前在using语句中实现IDisposable或包装代码是否给您带来了问题?

    谢谢

    5 回复  |  直到 14 年前
        1
  •  5
  •   Christian Hayter    14 年前

    我会说,永远使用 using 除非文档告诉您不要这样做(如您的示例所示)。

    有一个 Dispose

    PS:这里有一个简单实用的方法来补偿WCF的行为。这确保了 Abort Close 调用,并将错误传播给调用者。

    public static void CallSafely<T>(ChannelFactory<T> factory, Action<T> action) where T : class {
        var client = (IClientChannel) factory.CreateChannel();
        bool success = false;
        try {
            action((T) client);
            client.Close();
            success = true;
        } finally {
            if(!success) {
                client.Abort();
            }
        }
    }
    

    如果您在框架的其他地方发现任何其他有趣的行为案例,您可以提出一个类似的策略来处理它们。

        2
  •  3
  •   Abel    14 年前

    一般的经验法则很简单:当类实现IDisposable时,使用 using try / catch finally ,以便能够捕捉错误。

    然而,也有一些观察。

    1. 您询问是否存在不应使用IDisposable的情况。嗯:在大多数情况下,你不需要实现它。当您希望及时释放资源时使用它,而不是等待终结器启动。

    2. 在Dispose中抛出异常是不受欢迎的,当它发生时,状态可能不再得到保证。处境恶劣。您可以使用try/catch/finally来修复它,并在finally块中添加另一个try/catch。但就像我说的:很快就会变丑。

    3. 使用 是一回事,但不要把它和使用 尝试 最后

      {
          SomeType withDispose = new SomeType();
          try
          {
               // use withDispose
          }            
          finally 
          {
              if (withDispose != null)
              {
                   ((IDisposable)withDispose).Dispose();
              }
          }
      }
      
    4. 有时不需要将对象包装到using块中。这种情况很少见。当您发现自己从从IDisposable继承的接口继承时,就会发生这种情况 孩子需要处理。一个经常使用的例子是IComponent,它与每个控件(Form、EditBox、UserControl,您可以自己命名)一起使用。我很少看到人们用语句包装所有这些控件。另一个著名的例子是 IEnumerator<T>

    结论

    广泛地使用using语句,并且要明智地选择其他语句或将其忽略。确保你知道(而不是)使用它的含义,并意识到它的平等性 最后试试。需要抓点什么吗?使用try/catch/finally。

        3
  •  2
  •   jdmichal    14 年前

    我认为更大的问题是抛出异常 Dispose . RAII模式通常明确指出不应该这样做,因为它可以创建类似这样的情况。我的意思是,除了简单地结束执行之外,对于没有正确处理的东西,恢复路径是什么?

    try
    {
        using(...)
        {
            try
            {
                // Do stuff
            }
            catch(NonDisposeException e)
            {
            }
        }
    }
    catch(DisposeException e)
    {
    }
    

    这里唯一的问题是 DisposeException 是相同的还是超类型的 NonDisposeException ,而你正试图从 接住。在这种情况下 处置例外 布洛克会抓住的。因此,您可能需要一些额外的布尔标记来检查这一点。

        4
  •  2
  •   John Saunders    14 年前

    我只知道WCF客户端。这是由于WCF中的一个设计错误-Dispose应该 从未 抛出异常。他们错过了那个。

        5
  •  1
  •   Brian Gideon    14 年前

    IAsyncResult.AsyncWaitHandle 财产。精明的程序员会认识到这一点 WaitHandle 类实现 IDisposable 自然地尝试贪婪地处理它们。除了BCL中APM的大多数实现实际上对 等待句柄

    那么故障在哪里呢?微软搞砸了 IAsyncResult IAsyncResult公司 会从 可识别的 因为这意味着它拥有可支配的资源。精明的程序员会打电话来 Dispose IAsyncResult公司 让它决定如何最好地处理它的成分。

    这是典型的边缘案件之一 可能有问题。杰弗里·里克特实际上用这个例子来论证(在我看来是错误的)呼叫 不是强制性的。你可以读辩论 here