Ya sabes, mucha gente inteligente dice "use IDisposable si quiere implementar RAII en C#", y simplemente no lo compro. Sé que soy una minoría aquí, pero cuando veo "using (blah) {foo (blah);}" automáticamente pienso "blah contiene un recurso no administrado que debe limpiarse agresivamente tan pronto como foo termine (o throws) para que otra persona pueda usar ese recurso ". No creo que "blah no contenga nada interesante, pero hay un poco de semánticamente mutación importante que debe suceder, y vamos a representar esa operación semánticamente importante del personaje '}'": se debe realizar alguna mutación como alguna pila reventado o alguna bandera tiene que ser reiniciado o lo que sea.
Digo que si tiene una operación semánticamente importante que tiene que hacerse cuando algo se completa, tenemos una palabra para eso y la palabra es "finalmente". Si la operación es importante, entonces se debe representar como una declaración que se puede ver allí y poner un punto de interrupción, no un efecto secundario invisible de un corsé derecho.
Así que pensemos en su operación particular.Que desea representar:
var oldPosition = form.CursorPosition;
form.CursorPosition = newPosition;
blah;
blah;
blah;
form.CursorPosition = oldPosition;
Ese código es perfectamente claro . Todos los efectos secundarios están ahí, visibles para el programador de mantenimiento que quiere entender qué está haciendo su código.
Ahora tiene un punto de decisión. ¿Qué pasa si blah lanza? Si blah arroja entonces sucedió algo inesperado. Ahora no tienes ni idea de qué es la "forma" de estado; podría haber sido un código en "forma" que arrojó. Pudo haber estado a la mitad de alguna mutación y ahora está en un estado completamente loco.
Teniendo en cuenta esa situación, ¿qué quieres hacer?
1) Señale el problema a otra persona. Hacer nada. Espero que alguien más en la pila de llamadas sepa cómo manejar esta situación. Motivo de que el formulario ya está en mal estado; el hecho de que su cursor no está en el lugar correcto es la menor de sus preocupaciones. No toque algo que ya es tan frágil, se informó una excepción una vez.
2) Restablezca el cursor en un bloque finally y luego informe el problema a alguien más. Espero, sin ninguna evidencia de que se realice su esperanza, que restablecer el cursor en un formulario que sabe que está en un estado frágil no arroje una excepción. Porque, ¿qué pasa en ese caso? La excepción original, que tal vez alguien sabía cómo manejar, se pierde. Tiene información destruida sobre la causa original del problema, información que podría haber sido útil. Y lo ha reemplazado con otra información sobre un fallo de movimiento del cursor que no sirve a nadie.
3) Escriba la lógica compleja que maneja los problemas de (2): capte la excepción y luego intente restablecer la posición del cursor en un bloque try-catch-finally separado que suprima la nueva excepción y vuelva a lanzar el excepción original. Puede ser complicado acertar, pero puedes hacerlo.
Francamente, mi creencia es que la respuesta correcta es casi siempre (1). Si algo horrible salió mal, entonces no se puede razonar con seguridad sobre qué otras mutaciones al estado frágil son legales. Si no sabes cómo manejar la excepción, DÉ EN VUELTA.
(2) es la solución que te ofrece RAII con un bloque de uso. Una vez más, la razón por la que tenemos que usar bloques en primer lugar es para limpiar de manera agresiva los recursos vitales cuando ya no se pueden usar. Independientemente de si se produce una excepción o no, esos recursos deben limpiarse rápidamente, por lo que los bloques "que usan" tienen una semántica "finalmente". Pero la semántica "finalmente" no es necesariamente apropiada para operaciones que no son operaciones de limpieza de recursos; como hemos visto, los bloques finalmente cargados de semántica de programa suponen implícitamente que siempre es seguro realizar la limpieza; pero el hecho de que estamos en una situación de manejo de excepción indica que podría no ser seguro.
(3) parece mucho trabajo.
Así que, en resumen, digo que dejes de intentar ser tan inteligente. Desea mutar el cursor, hacer algo de trabajo y quitar el mudo del cursor. Entonces escribe tres líneas de código que hagan eso, listo. No se necesitan pantalones RAII de fantasía. simplemente agrega una indirección innecesaria, hace que sea más difícil leer el programa, y lo hace potencialmente más frágil en situaciones excepcionales, no menos frágil.
FYI, C# no tiene destructores en el mismo sentido que C++. Tiene finalizadores, pero se llaman en el momento de la recolección de elementos no utilizados, no cuando el objeto queda fuera del alcance. –