Il n'est pas totalement vrai que finally
sera toujours exécuté. Voir cette réponse de Haacked :
Deux possibilités :
StackOverflowException
ExecutingEngineException
Le bloc final ne sera pas exécuté lorsqu'il y a une StackOverflowException puisqu'il n'y a pas de place sur la pile pour pour exécuter du code supplémentaire. Il ne sera ne sera pas non plus appelé en cas d'exception d'une ExecutingEngineException, ce qui est très rare.
En fait, pour toute sorte d'exception asynchrone (telle que StackOverflowException
, OutOfMemoryException
, ThreadAbortException
) l'exécution d'un finally
n'est pas garanti.
Cependant, ces exceptions sont des exceptions dont vous ne pouvez généralement pas vous remettre, et dans la plupart des cas, votre processus se terminera de toute façon.
En fait, il y a aussi au moins un autre cas où finally
n'est pas exécuté comme décrit par Brian Rasmussen dans un maintenant question supprimée :
L'autre cas que je connais est celui où un finaliseur lève une exception. Dans ce cas, le processus cas, le processus est terminé immédiatement aussi, et donc la garantie garantie ne s'applique pas.
Le code ci-dessous illustre le problème
static void Main(string[] args) {
try {
DisposableType d = new DisposableType();
d.Dispose();
d = null;
GC.Collect();
GC.WaitForPendingFinalizers();
} catch {
Console.WriteLine("catch");
} finally {
Console.WriteLine("finally");
}
}
public class DisposableType : IDisposable {
public void Dispose() {
}
~DisposableType() {
throw new NotImplementedException();
}
}
Un try/catch/finally fiable devra utiliser Régions d'exécution sous contrainte (CER) . Un site exemple est fourni par MSDN :
[StructLayout(LayoutKind.Sequential)]
struct MyStruct
{
public IntPtr m_outputHandle;
}
sealed class MySafeHandle : SafeHandle
{
// Called by P/Invoke when returning SafeHandles
public MySafeHandle()
: base(IntPtr.Zero, true)
{
}
public MySafeHandle AllocateHandle()
{
// Allocate SafeHandle first to avoid failure later.
MySafeHandle sh = new MySafeHandle();
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
MyStruct myStruct = new MyStruct();
NativeAllocateHandle(ref myStruct);
sh.SetHandle(myStruct.m_outputHandle);
}
return sh;
}
}
L'article suivant constitue une excellente source d'information :
Meilleures pratiques en matière de fiabilité
4 votes
Non. Vous obtiendrez une erreur de compilation.
6 votes
La seule chose qui ne compile pas est le point-virgule manquant après la déclaration de 'ext'.
1 votes
@Zano - Le ; manquant était une faute de frappe :)
2 votes
Si le programme se plante au-delà de toute espérance (une erreur d'exécution catastrophique est une telle exception, généralement créée par l'appel d'un code P/Invoke qui perturbe la pile), ou si la machine perd de l'énergie, alors non, le bloc final ne s'exécutera pas.
0 votes
@Charles Pourquoi le devrait-il ? catch(Exception) est parfaitement bien, il n'est pas nécessaire de spécifier une variable pour "attraper dans".
0 votes
@Michael - vous avez raison - j'ai oublié cela.