Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"using" construct and exception handling

The "using" construct looks incredibly handy for situations that require both beginning and separated end parts.

Quick example to illustrate:

using (new Tag("body")) {
    Trace.WriteLine("hello!");
}
// ...
class Tag : IDisposable {
    String name;
    public Tag(String name) {
        this.name = name;
        Trace.WriteLine("<" + this.name + ">");
        Trace.Indent();
    }
    public void Dispose() {
        Trace.Unindent();
        Trace.WriteLine("</" + this.name + ">")
    }
}

The beginning part is defined as the constructor, the end part is the Dispose method.

However despite of being attractive this construct has a serious caveat that comes from the fact that the Dispose method is called from within a finally block. So there are 2 problems:

  1. You should avoid throwing exceptions from the finally block because they will override the original exception that was supposed to be caught.

  2. There is no way of knowing inside of the Dispose method if an exception was thrown earlier between "beginning" and "end" and thus there is no way of handling the "end" part accordingly.

These 2 things make using of this construct impractical which is a very sad fact. Now, my questions are:

  1. Is my understanding of the problems right? Is this how "using" actually works?

  2. If so, is there any way to overcome these problems and make practical use of the "using" construct other than what it was originally designed for (releasing resources and cleaning up)

  3. In case there is no practical way for "using" to be used this way. What are the alternative approaches (to enforce the context over some code with the beginning and end parts)?

like image 703
Trident D'Gao Avatar asked Jun 28 '12 14:06

Trident D'Gao


People also ask

Is it OK to throw exception in constructor?

The short answer to the question “can a constructor throw an exception in Java” is yes! Of course, properly implementing exceptions in your constructors is essential to getting the best results and optimizing your code.

What is example of exception handling?

Example: Exception handling using try... In the example, we are trying to divide a number by 0 . Here, this code generates an exception. To handle the exception, we have put the code, 5 / 0 inside the try block. Now when an exception occurs, the rest of the code inside the try block is skipped.

What is exception handling Handling?

Exception handling is the process of responding to unwanted or unexpected events when a computer program runs. Exception handling deals with these events to avoid the program or system crashing, and without this process, exceptions would disrupt the normal operation of a program.

What is exception and exception handling explain with example?

An exception occurs when an unexpected event happens that requires special processing. Examples include a user providing abnormal input, a file system error being encountered when trying to read or write a file, or a program attempting to divide by zero.


2 Answers

Your rule #1 applies with or without using, so the rule #2 is the real decider: opt for a try/catch if you must distinguish between situations when an exception has been thrown and the normal program completion.

For example, if your persistence layer may discover issues in the process of using a database connection, your connection needs to close regardless of the fact that there was an exception. In this case, the using construct is a perfect choice.

In some cases you can set up using specifically to detect normal completion vs. an exceptional completion. Ambient transactions provide a perfect example:

using(TransactionScope scope = new TransactionScope()) {
    // Do something that may throw an exception
    scope.Complete();
}

If scope's Dispose is called before Complete has been called, TransactionScope knows that an exception has been thrown, and aborts the transaction.

like image 168
Sergey Kalinichenko Avatar answered Oct 13 '22 00:10

Sergey Kalinichenko


The intent of the using statement and of the IDisposable interface is for the user to dispose of unmanaged resources. These resources are usually expensive and precious, so they must be disposed of no matter what (that's why it's on the finally). Code in finally blocks can't even be aborted, and it can hang a whole app domain shutdown.

Now, it's very tempting to abuse using for the purposes you're describing, and I've done that in the past. Most of the time there's no danger there. But if an unexpected exception happens, the whole state of the processing is compromised, you wouldn't necessarily want to run the end operation; so in general, don't do this.

An alternative is to use a lambda, something like this:

public interface IScopable { 
  void EndScope();
}

public class Tag : IScopable {
  private string name;
  public Tag(string name) {
    this.name = name;
    Trace.WriteLine("<" + this.name + ">");
    Trace.Indent();
  }
  public void EndScope() {
    Trace.Unindent();
    Trace.WriteLine("</" + this.name + ">");
  }
}

public static class Scoping {
  public static void Scope<T>(this T scopable, Action<T> action) 
    where T : IScopable {
    action(scopable);
    scopable.EndScope();
  }
}

Use it like this:

new Tag("body").Scope(_ => 
  Trace.WriteLine("hello!")
);

You can also create other implementations that run certain actions based on whether exceptions were raised of not.

In Nemerle, the language can be extended with new syntax to support this.

like image 39
Jordão Avatar answered Oct 13 '22 02:10

Jordão