Pourquoi utiliser try {} enfin {} avec un bloc try vide?

239

J'ai remarqué que System.Threading.TimerBase.Dispose()la méthode a un try{} finally{}bloc mais le try{}est vide.

Y a-t-il une valeur à utiliser try{} finally{}avec un vide 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
la source
System.Diagnostics.Process autour de la ligne 2144 également: referencesource.microsoft.com/#System/services/monitoring/…
Patrick Artner

Réponses:

171

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

Cette méthodologie protège contre un appel Thread.Abort interrompant le traitement. La page MSDN de Thread.Abort indique que «les blocs non exécutés sont finalement exécutés avant que le thread ne soit abandonné». Ainsi, afin de garantir que votre traitement se termine même si votre thread est abandonné au milieu par quelqu'un appelant Abort sur votre thread, vous pouvez placer tout votre code dans le bloc finally (l'alternative est d'écrire du code dans le bloc «catch» pour déterminez où vous vous trouviez avant que «l'essai» ne soit interrompu par Abort et poursuivez à partir de là si vous le souhaitez).

danben
la source
6
Pourquoi ne pas utiliser msdn.microsoft.com/en-us/library/… ?
Rob Fonseca-Ensor
15
Parce que ce n'était pas disponible avant .NET 2.0
Hans Passant le
6
@ RobFonseca-Ensor: Parce que Thread.BeginCriticalRegion()ne pas empêcher un fil d'être avorté, dit plutôt le moteur d' exécution que si un thread est interrompu, alors état global est corrompu, et l'ensemble est appdomain jusqu'à un meurtre par compassion.
kkm
9
@HansPassant: BeginCriticalSection()n'était vraiment pas là dans .NET 1.x, mais il n'y a pas de cause à effet que vous impliquez en disant parce que . En fait, dans .NET 1.x, même un finallybloc aurait pu être interrompu par un abandon de thread. Ces mécanismes ont un objectif différent: effectuer un travail dans a finallyempêche l'abandon à mi-chemin dans le code, tout en BeginCriticalSection()déclarant uniquement à l'exécution que l'état global est menacé.
kkm
Si le développeur a un certain temps (vrai) dans l'interruption définitive, l'annulation serait-elle jamais terminée ou pourrait-elle être ignorée techniquement indéfiniment?
Max Young
64

Il s'agit de se prémunir contre l' Thread.Abortinterruption d'un processus. La documentation de cette méthode indique que:

Enfin, les blocs non exécutés sont exécutés avant l'abandon du thread.

En effet, afin de récupérer avec succès après une erreur, votre code devra être nettoyé après lui-même. Étant donné que C # n'a pas de destructeurs de style C ++, finallyet les usingblocs sont le seul moyen fiable de garantir que ce nettoyage est effectué de manière fiable. N'oubliez pas que le usingbloc se transforme en ceci par le compilateur:

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

Dans .NET 1.x, il était possible que le finallybloc soit abandonné. Ce comportement a été modifié dans .NET 2.0.

De plus, les tryblocs vides ne sont jamais optimisés par le compilateur.

Anton Gogolev
la source
Merci pour la perspicacité sur le bloc d'utilisation.
Stefan
@Anton Je comprends que l'utilisation est une meilleure pratique. Mais à des fins de simulation, une classe wrapper doit parfois être implémentée et l'objet jetable devient une variable de classe privée. Si nous rendons ce wrapper jetable, le GC ne gère-t-il pas automatiquement la suppression de la variable de classe privée?
Ozkan
@Ozkan le GC ne dispose de rien automatiquement. Vous devez implémenter un finaliseur, appelant généralement a Dispose(false);. docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
Thorarin le
@Thorarin désolé mais vous vous trompez en disant que GC ne supprime pas (finalisation) automatiquement.
Ozkan