¿Por qué usar try {} finally {} con un bloque try vacío?

239

Noté que en System.Threading.TimerBase.Dispose()el método hay un try{} finally{}bloque pero try{}está vacío.

¿Hay algún valor en usar try{} finally{}con un vacío try?

http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Threading&type=TimerBase

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Dispose(WaitHandle notifyObject)
{
    bool status = false;
    bool bLockTaken = false;
    RuntimeHelpers.PrepareConstrainedRegions();
    try {
    }
    finally {
        do {
            if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
                bLockTaken = true;
                try {
                    status = DeleteTimerNative(notifyObject.SafeWaitHandle);
                }
                finally {
                    m_lock = 0;
                }
            }
            Thread.SpinWait(1);
            // yield to processor
        }
        while (!bLockTaken);
        GC.SuppressFinalize(this);
    }

    return status;
}
Samuel Neff
fuente
Sistema.Diagnóstico.Proceso alrededor de la línea 2144 también: referencesource.microsoft.com/#System/services/monitoring/…
Patrick Artner

Respuestas:

171

De http://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/ :

Esta metodología protege contra una llamada Thread.Abort que interrumpe el procesamiento. La página de MSDN de Thread.Abort dice que "Los bloques no ejecutados finalmente se ejecutan antes de que se cancele el hilo". Por lo tanto, para garantizar que su procesamiento finalice, incluso si su hilo se interrumpe en el medio por alguien que llama a Abortar en su hilo, puede colocar todo su código en el bloque finalmente (la alternativa es escribir código en el bloque "catch" para determine dónde estaba antes de que Abort interrumpiera el "intento" y proceda desde allí si lo desea).

danben
fuente
66
¿Por qué no usar msdn.microsoft.com/en-us/library/… ?
Rob Fonseca-Ensor
15
Porque eso no estaba disponible hasta .NET 2.0
Hans Passant
66
@ RobFonseca-Ensor: Porque Thread.BeginCriticalRegion()no evita que un hilo sea abortado, más bien le dice al tiempo de ejecución que si un hilo es abortado, entonces el estado global está corrupto, y todo el dominio de la aplicación está a punto de matar.
kkm
99
@HansPassant: BeginCriticalSection()realmente no estaba allí en .NET 1.x, pero no hay causa y efecto, lo que implica decir porque . De hecho, en .NET 1.x, incluso un finallybloque podría haber sido interrumpido por un aborto de subprocesos. Estos mecanismos tienen un propósito diferente: hacer el trabajo en un finallypreviene abortar a mitad de camino en el código, mientras que BeginCriticalSection()solo declara en el tiempo de ejecución que el estado global está en riesgo.
kkm
Si el desarrollador tiene un tiempo (verdadero) en el final, ¿el aborto alguna vez se completará o técnicamente se podría ignorar un aborto indefinidamente?
Max Young
64

Esto es para evitar Thread.Abortinterrumpir un proceso. La documentación para este método dice que:

Finalmente, los bloques no ejecutados se ejecutan antes de que se cancele el subproceso.

Esto se debe a que para recuperarse con éxito de un error, su código deberá limpiarse después de sí mismo. Dado que C # no tiene destructores de estilo C ++, finallyy los usingbloques son la única forma confiable de garantizar que dicha limpieza se realice de manera confiable. Recuerde que el usingbloque se convierte en esto por el compilador:

try {
    ...
}
finally {
    if(obj != null)
        ((IDisposable)obj).Dispose();
}

En .NET 1.x, existía la posibilidad de que el finallybloque se abortara. Este comportamiento se cambió en .NET 2.0.

Además, tryel compilador nunca optimiza los bloques vacíos .

Anton Gogolev
fuente
Gracias por la información sobre el bloque de uso.
Stefan
@Anton Entiendo que usar es una mejor práctica. Pero para fines de burla, a veces es necesario implementar una clase contenedora y el objeto desechable se convierte en una variable de clase privada. Si hacemos que este contenedor sea desechable, ¿no está GC manejando la eliminación de la variable de clase privada automáticamente?
Ozkan
@Ozkan the GC no elimina nada automáticamente. Tendría que implementar un finalizador, normalmente llamando a Dispose(false);. docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
Thorarin
@Thorarin lo siento pero te equivocas al decir que GC no se deshace (finaliza) automáticamente.
Ozkan