Michi said:
I don't think it's a bug in Mono because, as far as I can see, the spec
doesn't guarantee that either writing to the console or doing an assert
Are you sure it's because System.Console is finalized? it's not actively
closed by the runtime when terminating the application?
Anyway, you can do GC.SuppressFinalize(System.Console) to prevent it
from being finalized. Note that you may need to SuppressFinalize some
more things to get through this (see below).
is safe within a finalizer. After all, the spec quite clearly says
that the order of finalization is undefined. So, given that, I don't think
I can expect assert to work correctly during process shutdown.
The order of finalization of objects "elegible for destruction" is
undefined, but hopefully System.Console isn't elegible for destruction
untill your object is collected.
Looking at Ecma TC39-TG2/2004/14, the relevant statement must be section
10.9-2 at p. 101:
"If no part of the object can be accessed by any possible continuation
of execution, other than the running
of destructors, the object is considered no longer in use, and it
becomes eligible for destruction. [Note:
Implementations might choose to analyze code to determine which
references to an object can be used in
the future. For instance, if a local variable that is in scope is the
only existing reference to an object, but
that local variable is never referred to in any possible continuation of
execution from the current
execution point in the procedure, an implementation might (but is not
required to) treat the object as no
longer in use. end note]"
I have previously interpreted "by any possible continuation of
execution, other than the running of destructors" as disregarding code
actually in destructors, not calls to external functions. This would
prevent System.Console from being "elegible for destruction".
Unfortunatly, the formulation can also be read as "you can disregard any
references in code run in destructors, directly or indirectly" when
determining what is "elegible for destruction", which *would* let
System.Console be "elegible for destruction" before your destructor is run.
I had not considered this interpretation before, It would be nice to
know if this was the intended meaning. Especially, this interpretation
would allow the GC to actually *collect*, not only finalize, objects
only referenced (in code) in destructors at *any* time. I have a hard
time believing that is the intention.
I can see that this interpretation is required to be able to guarantee
that the finalizer can be run for all objects, otherwise cyclic
dependent finalizers would never render an object "elegible for
destruction", but really...