代码之家  ›  专栏  ›  技术社区  ›  Mr. Boy

捕捉Using块的目标对象的构造函数中抛出的异常

  •  5
  • Mr. Boy  · 技术社区  · 14 年前
    using(SomeClass x = new SomeClass("c:/temp/test.txt"))
    {
    ...
    }
    

    在使用块内,一切正常,例外情况正常。但是如果 SomeClass 是否可以引发异常?

    5 回复  |  直到 14 年前
        1
  •  4
  •   this. __curious_geek    14 年前

    是的 您所能做的就是将using块包装在try/catch块中。 这就是为什么你必须这样做。

    using块只是语法糖,编译器用等效的try/finall块替换每个using块。唯一的问题是编译器没有在try块中包装构造函数。编译后的代码将在IL中进行以下转换。

            //Declare object x of type SomeClass.
            SomeClass x;
    
            //Instantiate the object by calling the constructor.
            x = new SomeClass("c:/temp/test.txt");
    
            try
            {
                //Do some work on x.
            }
            finally
            {
                if(x != null)
                    x.Dispose();
            }
    

    从代码中可以看到,当构造函数抛出异常时,对象x不会被实例化,如果不处理,控件也不会从异常引发点进一步移动。

    blog-post on my blog 昨晚关于这个问题。

    我只是想知道为什么C# 试块内施工 我认为应该是 完成。

    我想我找到了答案,为什么C#没有将对象构造包装到try块中,而不是使用块。

    原因很简单。如果将声明和实例化都包装在try块中,那么 the object would be out of scope for the proceeding finally block 代码不会编译,因为finally block对象几乎不存在。如果只将构造包装在try块中,并在try块之前保留声明,即使在这种情况下,它也不会编译,因为它找到了 you're trying to use an assigned variable .

        2
  •  5
  •   Łukasz W.    14 年前

    把你的注意力放在抓球上。

    try
    {
       using(SomeClass x = new SomeClass("c:/temp/test.txt"))
       {
           ...
       }
    }
    catch(Exception ex)
    {
       ...
    }
    
        3
  •  1
  •   Chris McAtackney    14 年前

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (OtherClass inner = new OtherClass())
                {
                    Console.WriteLine("Everything is fine");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            Console.Read();
        }
    }
    
    class OtherClass : IDisposable
    {
        public OtherClass()
        {
            throw new Exception("Some Error!");
        }
    
        void IDisposable.Dispose()
        {
            Console.WriteLine("I've disposed my resources");
        }
    }
    

    输出:

    我已经处理了我的资源

    可能这是因为从未创建过对象,所以没有可调用的Dispose。

        4
  •  0
  •   John Saunders Tony    14 年前

    对于设计良好的类来说,这应该不是问题。记住整个问题:

    public class HoldsResources : IDisposable
    {
        public HoldsResources()
        {
            // Maybe grab some resources here
            throw new Exception("whoops");
        }
    }
    
    using (HoldsResources hr = new HoldsResources())
    {
    }
    

    所以,问题是,你应该怎么处理政府分配的资源 HoldsResources 在它引发异常之前?

    关于那些资源。那不是你的工作。当决定 控股资源 会持有资源,这就带来了妥善处置资源的义务。这意味着在构造函数中有try/catch/finally块,这意味着 IDisposable 把这些资源处理掉 Dispose 方法。

    责任是使用 using 阻止呼叫他的 处置 方法,当您使用完实例时。没别的了。

        5
  •  -1
  •   Robert Giesecke    14 年前

    此示例显示了一个ctor,它可以在出现问题时防止泄漏,当您在工厂方法中分配一次性物品时,同样的规则也适用。

    class Sample
    {
      IDisposable DisposableField;
    
      ...
    
      public Sample()
      {
        var disposable = new SomeDisposableClass();
        try
        {
           DoSomething(disposable);
           DisposableField = disposable;
        }
        catch
        {
           // you have to dispose of it yourself, because
           // the exception will prevent your method/ctor from returning to the caller.
           disposable.Dispose();
           throw;
        }
      }
    }
    

    编辑

    当然,这样做的原因是:当你调用工厂或ctor时,你只能处理它的结果。当电话接通时,你必须假设到目前为止一切正常。

    当你打电话给一个医生或工厂的时候,你不需要做任何反向的精神分析来处理任何你无论如何都拿不到的东西。如果它确实抛出异常,那么在重新抛出异常之前,工厂/ctor有责任清除分配的一半。 (希望,这一次,已经够详细了……)