C# 如何处理一次性对象引发的异常?

C# 如何处理一次性对象引发的异常?,c#,idisposable,C#,Idisposable,假设构造函数和进程方法可能引发异常,那么使用一次性对象的最佳方法是什么?我通常更喜欢以下实现之一 尝试使用块捕捉周围 try { using (Disposable dispObj = new Disposable()) { dispObj.Process(); } } catch (Exception ex) { // Do something } 试着抓住最后一块 Disposable dispObj2 = null; try {

假设构造函数和进程方法可能引发异常,那么使用一次性对象的最佳方法是什么?我通常更喜欢以下实现之一

  • 尝试使用块捕捉周围

    try
    {
        using (Disposable dispObj = new Disposable())
        {
            dispObj.Process();
        }
    }
    catch (Exception ex)
    {
        // Do something
    }
    
  • 试着抓住最后一块

    Disposable dispObj2 = null;
    try
    {
        dispObj2 = new Disposable();
        dispObj2.Process();
    }
    catch (Exception ex)
    {
        // Do something
    }
    finally
    {
        if (dispObj2 != null)
        {
            dispObj2.Dispose();
        }
    }
    
  • 更新:


    同样:“假设构造函数和进程方法可能引发异常”。我真的不明白为什么没有人关心他们答案中的例外情况。

    使用
    是好的。它有一个内置的try finally块。若发生异常,将自动调用dispose方法

    这很好

    using (Disposable dispObj = new Disposable())
    {
        dispObj.Process();
    }
    
    这样做:

    using (Disposable dispObj = new Disposable())
    {
        dispObj.Process();
    }
    
    IDisposable disp = new IDisposable();
    
    try
    {
      //some logic here
    }
    finally
    {
      if (disp != null)
         ((IDisposable)disp).Dispose();
    }
    
    使用子句时,当一次性对象超出
    的范围时,始终会对其进行处置,即使这是由异常引起的


    不要使用空的
    catch{}
    ,它完全没有意义。

    在可能的情况下,应该使用using块。它将保证对对象调用Dispose。手动执行此操作容易出错。

    实现IDisposable接口的类通常使用.NET framework垃圾收集器无法清理的资源。 调用IDisposable.Dispose()方法执行显式释放宝贵资源的代码。 实现IDisposable接口的类的一个主要示例是SqlConnection类。SqlConnection类使用Microsoft SQL Server数据库连接。由于SQL Server支持有限数量的连接,因此尽快释放连接非常重要。
    通常,您不会直接调用Dispose()方法。通常,您可以在代码中利用Using语句,就像您在代码中提到的那样,Using语句在后台使用try-finally,并且只与实现IDisposable的对象一起工作。你不必用try-catch和using。请看下面的示例(来自)

    上述代码与以下代码相同:

    Font font1 = new Font("Arial", 10.0f);
      try
      {
        byte charset = font1.GdiCharSet;
      }
      finally
      {
        if (font1 != null)
          ((IDisposable)font1).Dispose();
      }
    
    此代码将被翻译成如下内容:

    using (Disposable dispObj = new Disposable())
    {
        dispObj.Process();
    }
    
    IDisposable disp = new IDisposable();
    
    try
    {
      //some logic here
    }
    finally
    {
      if (disp != null)
         ((IDisposable)disp).Dispose();
    }
    
    块“finally”中的代码总是执行的,所以它给了您抛出异常的可能性,使您可以毫无疑问地从使用块返回Dispose而不会被调用

    但是在使用和对象初始值设定项时应该小心

    using (var fs = new FileStream(@"C:\blabla", FileMode.Open) { Position = pos })
    {
        //some logic here
    }
    
    正如您从属性中看到的,Position可以抛出异常。问题是对象将被创建,并且这将在try块外执行,所以可能会出现内存泄漏。正确的方法

    using (var fs = new FileStream(@"C:\blabla", FileMode.Open))
    {
        fs.Position = pos;
        //some logic here
    }
    
    你提出的方法#1可能是实现你想要的最简洁的方法

    周围的
    try
    catch
    块应该捕获抛出的任何异常,包括构造函数抛出的异常。如果在使用一次性对象时(在
    using
    块内)发生异常,则该对象也将在
    catch
    接管之前被处置

    方法2采用与方法1不同的执行路径。请注意,根据,方法#1按字面意思编译,就好像编写了以下内容:

    try
    {
        {
            Disposable dispObj = new Disposable();
            try
            {
                dispObj.Process();
            }
            finally
            {
                if (dispObj != null)
                    ((IDisposable)dispObj).Dispose();
            }
        }
    }
    catch (Exception ex)
    {
        // Do something
    }
    

    因此,这两种方法的范围是不同的。如果可能的话,我更喜欢方法#1,因为范围问题,也因为它更容易阅读。

    为什么空的
    catch{}
    ?您的类
    一次性的
    必须实现,顺便说一句。您还应该实现
    IDisposable
    来调用任何组合对象(无论是在成员字段还是属性中)上的
    Dispose
    实现
    IDisposable
    本身。如果构造函数或过程方法引发异常怎么办?那么它也会被处理。@NikhilAgrawal需要在注释中引用如果构造函数或过程方法引发异常怎么办?如果构造函数或过程方法引发异常怎么办?这就是
    使用
    子句的全部要点。即使发生异常,它也将始终处理在其中构造的对象。它基本上就像使用try/finally,只是写得少一些。我甚至在这个回答中这样说,我知道,但我想学习的是人们如何处理一次性物品引发的异常。try-catch-finally或try-catch-ounding-using-block或其他东西。如果您有一个一次性对象,并且希望以特定的方式处理异常,我建议使用try/catch/finally。在finally-dispose中,在catch-handle异常中。当然,这有点取决于您是否能够在代码中指出异常应该发生的位置,在这种情况下,您可能希望使用
    使用
    ,然后用try/catch将可能失败的部分包围起来。如果构造函数或进程方法引发异常怎么办?如果“某个逻辑”或“新文件流”方法引发异常怎么办?如果“new FileStream”抛出异常“OK”。对象未创建,所以没有要处理的内容。如果“有逻辑”抛出异常,dispose将从最后调用。好的,我知道,但异常处理如何?这个问题是:您更喜欢使用try-catch还是使用try-catch-finally或其他方法?第一种方法的一个问题是,如果
    using
    调用的
    Dispose
    方法抛出异常(可能是试图关闭弹出的USB驱动器上的文件)使用
    块本身无法知道
    中是否发生异常。在
    Dispose
    可能引发异常的情况下,最好在其中包含一个
    catch
    ,以确保引发的异常不会被覆盖。进一步阅读@supercat提出的问题:
    try
    {
        {
            Disposable dispObj = new Disposable();
            try
            {
                dispObj.Process();
            }
            finally
            {
                if (dispObj != null)
                    ((IDisposable)dispObj).Dispose();
            }
        }
    }
    catch (Exception ex)
    {
        // Do something
    }