Calling Dispose method inside constructor which throws an exception or behaves unexpectedly

Derek W

I have a class which consumes some unmanaged resources and I would like to free them deterministically and request that the finalizer not be called for the object at hand. My Dispose() method of the class accomplishes this.

In the event of an exception being thrown or something otherwise going wrong or behaving unexpectedly in the constructor, I would like to call Dispose() before throwing. However, I rarely come across implementations which catch thrown exceptions or handle an error in the constructor of disposable objects and then invoke Dispose() on the object - In a lot of cases the author leaves the cleanup to the finalizer. I have not read anything which states that calling Dispose() in a failed constructor is bad practice, but while looking through the .NET source code I have yet to come across such exception or error handling in a disposable object constructor.

Can I call Dispose() inside a "failed" constructor and still be considered a good coding citizen?

Edit to clarify - I am talking about inside the constructor:

public class MyClass : IDisposable
{
     private IntPtr _libPtr = IntPtr.Zero;

     public MyClass(string dllPath)
     {
         _libPtr = NativeMethods.LoadLibrary(dllPath);

         if (_libPtr != IntPtr.Zero)
         { 
             IntPtr fxnPtr = NativeMethods.GetProcAddress(_libPtr, "MyFunction");
             if (fxnPtr == IntPtr.Zero)
             {
                 Dispose(); // Cleanup resources - NativeMethods.FreeLibrary(_libPtr);
                 throw new NullReferenceException("Error linking library."); 
             }
         }
         else
         {
             throw new DllNotFoundException("Something helpful");
         }
     } 

     // ...
} 
Jon Hanna

I wouldn't have an object call Dispose on itself, but I certainly would have a constructor clean itself up if necessary. I'd also like to make that clean-up as simple as possible Considering your example, I'd prefer to compose it something like:

internal sealed class Library : IDisposable
{
  IntPtr _libPtr; // Or better yet, can we use or derive from SafeHandle?
  public Library(string dllPath)
  {
     _libPtr = NativeMethods.LoadLibrary(dllPath);
     if(_libPtr == IntPtr.Zero)
     {
       GC.SuppressFinalize(this);
       throw new DllNotFoundException("Library Load Failed");
     }
  }
  private void Release()
  {
    if(_libPtr != IntPtr.Zero)
      NativeMethods.FreeLibrary(_libPtr);
    _libPtr = IntPtr.Zero; // avoid double free even if a caller double-disposes.
  }
  public void Dispose()
  {
    Release();
    GC.SuppressFinalize(this);
  }
  ~Library()
  {
    Release();
  }
  public IntPtr GetProcAddress(string functionName)
  {
    if(_libPtr == IntPtr.Zero)
      throw new ObjectDisposedException();
    IntPtr funcPtr = NativeMethods.GetProcAddress(_libPtr, functionName);
    if(_funcPtr == IntPtr.Zero)
      throw new Exception("Error binding function.");
    return _funcPtr;
  }
}

So far nice and simple. Either this object is constructed successfully and can be released by the code that called it, or it doesn't need clean-up. We can even prevent the no-op finalisation, just to be nice. The main thing is that there's nothing that needs cleaned up created after the last thing that could reasonably go wrong.

And then:

public sealed class MyClass : IDisposable
{
  private readonly Library _lib;
  private readonly IntPtr _funcPtr;

  public MyClass(string dllPath)
  {
    _lib = new Library(dllPath); // If this fails, we throw here, and we don't need clean-up.

    try
    { 
      _funcPtr = _libPtr.GetProcAddress("MyFunction");
    }
    catch
    {
      // To be here, _lib must be valid, but we've failed over-all.
      _lib.Dispose();
      throw;
    }
  }
  public void Dispose()
  {
    _lib.Dispose();
  }
  // No finaliser needed, because no unmanaged resources needing finalisation are directly held.
}

Again, I can ensure clean-up, but I don't call this.Dispose(); While this.Dispose() could do the same trick, I mainly prefer to have the field I am cleaning up explicit in the same method (the constructor here) that set it but failed to do all of its job. For one thing, the only place there can be a partially-constructed object is in the constructor, so the only place I need be considering a partially-constructed object is in the constructor; I've made it an invariant of the rest of the class that _lib isn't null.

Let's imagine that functions had to be released separately from libraries, just to have a more complicated example. Then I would also wrap _funcPtr to keep with the simplifying rule; either a class has a single unmanaged resource that it cleans up through Dispose() and a finaliser, or it has one or more IDisposable fields that it cleans up through Dispose or it doesn't need disposal, but never a combination of the above.

internal sealed class Function : IDisposable
{
  IntPtr _funcPtr; // Again better yet, can we use or derive from SafeHandle?
  public Function(Lib library, string functionName)
  {
    _funcPtr = library.GetProcAddress(functionName);
    if(_funcPtr == IntPtr.Zero)
    {
      GC.SuppressFinalize(this);
      throw new Exception("Error binding function."); 
    }
  }
  private void Release()
  {
    if(_funcPtr != IntPtr.Zero)
      NativeMethods.HypotheticalForgetProcAddressMethod(_funcPtr);
    _funcPtr = IntPtr.Zero; // avoid double free.
  }
  public void Dispose()
  {
    Release();
    GC.SuppressFinalize(this);
  }
  ~Function()
  {
    Release();
  }
}

And then MyClass would be:

public sealed class MyClass : IDisposable
{
  private Library _lib;
  private Function _func;

  public MyClass(string dllPath)
  {
    _lib = new Library(dllPath); // If this fails, we throw here, and we don't need clean-up.
    try
    { 
      _func = new Function(_lib, "MyFunction");
      try
      {
        SomeMethodThatCanThrowJustToComplicateThings();
      }
      catch
      {
        _func.Dispose();
        throw;
      }
    }
    catch
    {
      _lib.Dispose();
      throw;
    }
  }
  public void Dispose()
  {
    _func.Dispose();
    _lib.Dispose();
  }
}

This makes the constructor a bit more verbose, and I'd rather avoid two things that can go wrong affecting two things that need clean-up in the first place. It does though reflect why I like the clean-up to be explicit as to the different fields; I might want to clean up both fields, or just one, depending on where the exception hits.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Java

Determining which method throws exception

From Dev

Reflectively call constructor which throws an exception

From Java

The method of an anonymous class behaves unexpectedly

From Dev

Test a method which throws an exception using Junit

From Dev

Mockito JUnit test on method which throws exception

From Dev

Calling a UI method from Isolate listen method in Flutter throws exception

From Dev

What is type of native constructor which throws exception in Frege?

From Dev

std::future still valid after calling get() (which throws an exception)

From Dev

Pop method for linked list behaves unexpectedly

From Java

Lambda return method which calls method that throws exception

From Java

Is the close method on a try-with-resources idiom not called if a constructor throws an exception?

From Dev

Calling a class method with scoped coroutine in Kotlin/Native on Linux throws exception

From Dev

Calling interface method in razor page throws unhandled exception

From Dev

calling method inside a method which takes some argument

From Dev

Test method which throws an exception as has Span as a parameter

From Java

How to invoke a method which throws an Exception using Java Reflection?

From Dev

Calling a method on a constructor method

From Dev

calling an overriden method inside a constructor of both the parent and sub classes

From Dev

Flutter: how to conditionally run method inside ChangeNotifier after calling constructor

From Dev

Calling private method from inside the constructor does not change values of variables

From Java

Calling methods inside Constructor

From Dev

What happens if a constructor throws an exception?

From Dev

YamlDotNet Serializer constructor throws exception

From Dev

Unreachable Statement in the constructor that throws exception

From Dev

Calling a method inside a method

From Java

throws Exception in a method with Kotlin

From Dev

Calling a void Method into a constructor

From Java

Calling method from constructor

From Dev

Calling a constructor as a method

Related Related

  1. 1

    Determining which method throws exception

  2. 2

    Reflectively call constructor which throws an exception

  3. 3

    The method of an anonymous class behaves unexpectedly

  4. 4

    Test a method which throws an exception using Junit

  5. 5

    Mockito JUnit test on method which throws exception

  6. 6

    Calling a UI method from Isolate listen method in Flutter throws exception

  7. 7

    What is type of native constructor which throws exception in Frege?

  8. 8

    std::future still valid after calling get() (which throws an exception)

  9. 9

    Pop method for linked list behaves unexpectedly

  10. 10

    Lambda return method which calls method that throws exception

  11. 11

    Is the close method on a try-with-resources idiom not called if a constructor throws an exception?

  12. 12

    Calling a class method with scoped coroutine in Kotlin/Native on Linux throws exception

  13. 13

    Calling interface method in razor page throws unhandled exception

  14. 14

    calling method inside a method which takes some argument

  15. 15

    Test method which throws an exception as has Span as a parameter

  16. 16

    How to invoke a method which throws an Exception using Java Reflection?

  17. 17

    Calling a method on a constructor method

  18. 18

    calling an overriden method inside a constructor of both the parent and sub classes

  19. 19

    Flutter: how to conditionally run method inside ChangeNotifier after calling constructor

  20. 20

    Calling private method from inside the constructor does not change values of variables

  21. 21

    Calling methods inside Constructor

  22. 22

    What happens if a constructor throws an exception?

  23. 23

    YamlDotNet Serializer constructor throws exception

  24. 24

    Unreachable Statement in the constructor that throws exception

  25. 25

    Calling a method inside a method

  26. 26

    throws Exception in a method with Kotlin

  27. 27

    Calling a void Method into a constructor

  28. 28

    Calling method from constructor

  29. 29

    Calling a constructor as a method

HotTag

Archive