2

If you run the following code then close the form you get a ObjectDisposedException "Cannot access a disposed object." despite the guard clause in the commented line (26).

What is a correct way to detect that a Form has been Dispose()d to prevent this exception from happening?

using System;
using System.Threading;
using System.Windows.Forms;

namespace DisposeExample
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            var handleCreated = new ManualResetEvent(false);
            Form form = null;
            ThreadStart createForm = () =>
            {
                form = new Form();
                form.Show();
                handleCreated.Set();
                Application.Run(form);
            };

            ThreadStart updateData = () =>
            {
                while (true)
                {
                    if (!form.IsDisposed) // this doesn't prevent ObjectDisposedException
//                        if (form.Visible) // this doesn't prevent ObjectDisposedException
                        form.Invoke((MethodInvoker)(() => form.Text = form.Text == "A" ? "B" : "A"));
                }
            };
            var updateDataThread = new Thread(updateData);
            updateDataThread.IsBackground = true;

            new Thread(createForm).Start();
            handleCreated.WaitOne();
            updateDataThread.Start();
        }
    }
}
Garrett Smith
  • 688
  • 1
  • 7
  • 24
  • @Sayse That makes no sense. The fact that there is no `NullReferenceException` here should already tell you that `form` *isn't* `null`. –  May 29 '14 at 10:32
  • @hvd - it appears I misunderstood, I believed that the form being disposed meant that the form was removed from memory – Sayse May 29 '14 at 10:34
  • It is an unsolvable threading race, you *must* ensure that the form cannot close until you know that the thread has exited. The programming style is very troublesome, displaying UI on a thread in the MTA can cause *lots* of misery, but a Q&D fix is Environment.Exit() in an event handler for the form's FormClosing event. – Hans Passant May 29 '14 at 11:10

1 Answers1

3

If you're disposing the object in a different thread, without any cross-thread synchonisation, there is simply no way. Think about it: if form.IsDisposed returns false, that different thread may then call form.Dispose() before you start your form.Invoke, or during.

You cannot reliably prevent ObjectDisposedException from being thrown, so just catch the exception and handle it.