How to handle all exceptions in a c # class where ctor and finalizer exceptions are thrown?

How can I handle all exceptions for a class like the following under certain circumstances?

class Test : IDisposable {
  public Test() {
    throw new Exception("Exception in ctor");  
  }
  public void Dispose() {
    throw new Exception("Exception in Dispose()");
  }
  ~Test() {
    this.Dispose();
  }
}

      

I tried this but it doesn't work:

static void Main() {
  Test t = null;
  try {
    t = new Test();
  }
  catch (Exception ex) {
    Console.Error.WriteLine(ex.Message);
  }

  // t is still null
}

      

I also tried using "using", but it doesn't handle the exception thrown from ~ Test ();

static void Main() {
  try {
    using (Test t = new Test()) { }
  }
  catch (Exception ex) {
    Console.Error.WriteLine(ex.Message);
  }
}

      

Any ideas how I can work?

+2


a source to share


3 answers


First, the Finalizer should never throw an exception. If so, something is catastrophically wrong and the application should crash badly. The finalizer should also never call Dispose () directly. Finalizers are only intended to release unmanaged resources, as managed resources might not even be in a valid state after the Finalizer is run. Managed references will already be garbage collected, so you'll only need to dispose of them in your Dispose, not in the Finalizer.

However, an exception in Dispose must be caught if you explicitly call Dispose. I don't have a good understanding of how the "use" case did not throw an exception. However, Dispose really shouldn't throw exceptions if you can avoid it. Specifically, Dispose, which throws an exception after the used block "overwrites" any exception that might occur inside a use block with a Dispose exception.




Some additional reference here

+5


a source


I think part of the answer is that you shouldn't be handling exceptions in these cases.



You should only catch exceptions if you can recover them, or if you can add additional information to exception and redo. You don't have to catch all exceptions. Let the code above in the call stack handle as many exceptions as possible.

+3


a source


I have several observations.

First, avoid throwing exceptions from Dispose. In fact, I would almost go so far as to never speak. The .NET developers have been conditioned to ensure that Dispose will always succeed, and for good reason. It would be awkward to terminate the call in try-catch every time, and it would certainly reduce readability.

Second, and this is a question that is often discussed in avoiding throwing exceptions from constructors. Stateful exceptions such as ArgumentException or IndexOutOfRangeException are fine because they are usually thrown from precondition violations and are usually the result of a programming error. But unpredictable exceptions like SqlException pretty much cause the caller to wrap the constructor in a try-catch block. Again, this leads to awkward coding scenarios. But more importantly, it can lead to subtle resource leaks in scenarios where the constructor allocates unmanaged resources and then throws an exception before returning a new instance to the caller. Without an instance reference, the caller cannot call Dispose.

+1


a source







All Articles