views:

101

answers:

5
using(SomeClass x = new SomeClass("c:/temp/test.txt"))
{
...
}

Inside the using block, all is fine with treating exceptions as normal. But what if the constructor of SomeClass can throw an exception?

+5  A: 

Put your using into the try catch f.e.

try
{
   using(SomeClass x = new SomeClass("c:/temp/test.txt"))
   {
       ...
   }
}
catch(Exception ex)
{
   ...
}
ŁukaszW.pl
This is not needed. See my answer to see why.
Oded
What answer? I can't see one.
John
Neither do I ;)
ŁukaszW.pl
A: 

I threw a quick test program together to check this, and it seems that the Dispose method does not get called when an exception is thrown in the constructor;

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");
    }
}

Output :

Some Error!

If you don't throw the exception..

Output :

Everything is fine

I've disposed my resources

Presumably this is because the object was never created, so there's nothing to call Dispose on.

I'm not sure what would happen if the constructor had already allocated some resources which would normally require a proper clean up through Dispose and the exception occurred afterwards though.

C.McAtackney
+3  A: 

Yes, this will be a problem when the constructor throws an exception. All you can do is wrap the using block within a try/catch block. Here's why you must do it that way.

using blocks are just syntactic sugar and compiler replaces each using block with equivalent try/finall block. The only issue is that the compiler does not wrap the constructor within the try block. Your code after compilation would have following conversion in the 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();
        }

As you can see from the code, the object x will not be instantiated in case when the constructor throws an exception and the control will not move further from the point of exception raise if not handled.

I have just posted a blog-post on my blog on this subject last night.

I'm just now wondering why C# designers did not wrap object construction within the try block which according to me should have been done.

EDIT

I think I found the answer why C# does not wrap object construction into try block generated in place of the using block.

The reason is simple. If you wrap both declaration and instantiation within the try block then the object would be out of scope for the proceeding finally block and the code will not compile at because, for finally block the object hardly exists. If you only wrap the construction in the try block and keep declaration before the try block, even in that case the it will not compile since it finds you're trying to use an assigned variable.

this. __curious_geek
A: 

When you get a hold of resources in the ctor that are not subject to garbage collection, you have to make sure to dispose of them when things go south.

This sample shows a ctor which will prevent a leak when something goes wrong, the same rules apply when you allocate disposables inside a factory method.

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;
    }
  }
}

Edit: I had to change my sample from a factory to a ctor, because apparantly it wasn't as easy to understand as I hoped it would be. (Judging from the comments.)

And of course the reason for this is: When you call a factory or a ctor, you can only dispose of its result. When the call goes through, you have to assume that everything's okay so far.

When calling a ctor or factory you don't have to do any reverse-psychoanalysis to dispose of anything you can't get hold of anyways. If it does throw an exception, it is in the factories/ctor's responsibility to clear anything half-allocated before re-throwing the exception. (Hope, this time, it was elaborate enough...)

Robert Giesecke
-1: IDisposable has nothing to do with garbage collection - it's about ending the use of resources, not of memory.
John Saunders
I'm not going to down vote, but this code doesn't answer the question of what happens when you throw an exception in the constructor of an object wrapped in a using statement. It just shows how to to do sort of what a using statement does manually.
Dave White
@John, I never said that it has anything directly to do with GC'ing. However, when you get hold of unmanaged resources in a ctor or factory, you better make sure that you dispose of them when your call cannot return. e.g. an exception in a ctor or fatory. @Dave How would you interpret his question? A using block will not handle any exceptions, it will just ensure that *only when the initializing expressions succeeds*, it will make sure to dispose of its result.
Robert Giesecke
@Robert: then why did you say, "When you get a hold of resources in the ctor that are not subject to garbage collection"?
John Saunders
Probably, because those are "**resources** in the ctor that are not subject to garbage collection" . ;-)
Robert Giesecke
A: 

This should not be a problem with a well-designed class. Remember the overall question:

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

using (HoldsResources hr = new HoldsResources())
{
}

So, the question is, what should you do about the resources allocated by the HoldsResources constructor before it threw an exception?

The answer is, you shouldn't do anything about those resources. That's not your job. When it was decided that HoldsResources would hold resources, that brought the obligation to properly dispose of them. That means a try/catch/finally block in the constructor, and it means proper implementation of IDisposable to dispose of those resources in the Dispose method.

Your responsibility is to use the using block to call his Dispose method when you're through using the instance. Nothing else.

John Saunders