¿Cómo puedo detener con gracia un System.Threading.Timer?

Tengo un servicio de Windows implementado en C # que necesita hacer algún trabajo de vez en cuando. He implementado esto usando unSystem.Threading.Timer con un método de devolución de llamada que es responsable de programar la próxima devolución de llamada. Estoy teniendo problemas para detener (es decir, desechar) el temporizador. Aquí hay un código simplificado que puede ejecutar en una aplicación de consola que ilustra mi problema:

const int tickInterval = 1000; // one second

timer = new Timer( state => {
                       // simulate some work that takes ten seconds
                       Thread.Sleep( tickInterval * 10 );

                       // when the work is done, schedule the next callback in one second
                       timer.Change( tickInterval, Timeout.Infinite );
                   },
                   null,
                   tickInterval, // first callback in one second
                   Timeout.Infinite );

// simulate the Windows Service happily running for a while before the user tells it to stop
Thread.Sleep( tickInterval * 3 );

// try to gracefully dispose the timer while a callback is in progress
var waitHandle = new ManualResetEvent( false );
timer.Dispose( waitHandle );
waitHandle.WaitOne();

El problema es que me sale unObjectDisposedException desdetimer.Change en el hilo de devolución de llamada mientraswaitHandle.WaitOne esta bloqueando ¿Qué estoy haciendo mal?

La documentación Para elDispose sobrecarga que estoy usando dice:

El temporizador no se elimina hasta que se hayan completado todas las devoluciones de llamada actualmente en cola.

Editar: Parece que esta declaración de la documentación puede ser incorrecta. ¿Alguien puede verificar?

Sé que podría solucionar el problema agregando alguna señalización entre la devolución de llamada y el código de eliminación como Henk Holterman sugirió a continuación, pero no quiero hacer esto a menos que sea absolutamente necesario.