Sperimentando in questi giorni delle cose, mi sono fermato su una prova che mi è apparsa piuttosto strana: il seguente snippet
using System;
class Foo
{
static int i = 0;
~Foo()
{
Foo f = new Foo();
Console.WriteLine(++i);
}
static void Main()
{
Foo foo = new Foo();
}
}
stampa a console numeri consecutivi e si ferma senza errore dopo qualche decina di migliaia!...
La spiegazione l'ho trovata solo adesso, dopo tante fantasie sognate, in una pagina (467) di Richter:
"Quando è in corso il regolare arresto di un processo," [...] "ciascun metodo Finalize ha circa 2 secondi di tempo per essere restituito. Se un metodo Finalize non viene restituito entro 2 secondi, CLR interromperà il processo e non saranno richiamati altri metodi Finalize. Inoltre, se per chiamare i metodi Finalize di tutti gli oggetti si superano i 40 secondi, allora di nuovo, CLR interromperà il processo.
Il codice in un metodo Finalize può costruire nuovi oggetti. Se questa operazione si verifica nel corso dell'arresto di CLR, CLR continuerà a raccogliere gli oggetti e a richiamare i relativi metodi Finalize fino a quando non vi saranno più oggetti o fino alla scadenza dei 40 secondi.
Nota. Questi valori di timeout erano corretti al momento in cui è stato scritto il testo; è possibile vengano modificati da Microsoft in futuro."
I numeri vengono stampati dallo snippet in meno di 40 secondi, ma non il valore del timeout è importante, bensì l'idea. Per esempio, con un valore di 3000 milisecondi passato al metodo Sleep questo snippet:
using System;
using System.Threading;
class Foo
{
~Foo()
{
Thread.Sleep(3000);
Console.WriteLine("Ciao");
}
static void Main()
{
Foo foo = new Foo();
}
}
non stampa nulla a console, mentre con un valore di 1000 milisecondi viene stampato Ciao (ho scelto due valori intorno ai 2 secondi, uno maggiore e l'altro minore).
Attenzione quindi ai tempi di esecuzione dei finalizer!