runtime: Dispose should not throw PlatformNotSupportedException even when the type is not supported

As reported by @ayende in a blog post, some types throw PlatformNotSupportedException from Dispose(bool disposing) on platforms that are not supported. This is problematic, because:

  1. The big issue: The finalizer of a base class of some of those types (like Component) calls Dispose(false), which causes the process to crash.

  2. The smaller issue: It’s against the Framework Design Guidelines:

    X AVOID throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted (leaks, inconsistent shared state, etc.).

    Users expect that a call to Dispose will not raise an exception.

    I think this applies even for types that are not supported.

The original example was SqlConnection, but I think a simpler repro is with SerialPort, which is not supported on .Net Core on Linux:

  1. The following should apply to any Linux machine with .Net Core installed (in my case, Ubuntu 16.04 and .Net Core SDK 2.0.3).

  2. dotnet new console

  3. dotnet add package System.IO.Ports

  4. Change Program.cs to:

    using System;
    using System.IO.Ports;
    
    class Program
    {
        static void Main()
        {
            try
            {
                new SerialPort();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
    
            // to simulate GC and subsequent finalization at some point in the future
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
    
  5. Run it in Release mode (to make sure the finalizer is run): dotnet run -c Release

  6. The program first correctly catches the exception thrown from the SerialPort constructor, but then it crashes:

    System.PlatformNotSupportedException: System.IO.Ports is currently only supported on Windows.
       at System.IO.Ports.SerialPort..ctor()
       at Program.Main() in /home/osboxes/hwapp/Program.cs:line 10
    
    Unhandled Exception: System.PlatformNotSupportedException: System.IO.Ports is currently only supported on Windows.
       at System.IO.Ports.SerialPort.Dispose(Boolean disposing)
       at System.ComponentModel.Component.Finalize()
    

I think that for unsupported types, Dispose should be empty. It should not throw, to avoid crash that cannot be prevented (and to follow Framework Design Guidelines).

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 8
  • Comments: 15 (14 by maintainers)

Most upvoted comments

Or just put in a no op line of code.