the thing is that your invariant is not a correct invariant at
all.
invariants are meant to check *internal* object consistency,
not external
conditions. compiler is free to call invariant block at any
time after
object is properly initialised (i.e. after ctor is complete)
and is not
executing member method. so it's perfectly legal to call
invariant before
dtor, as you should not check anything that is not belonging to
the
object itself in in.
in other words: you can't check any contents of any
reference-typed
variables in your invariant block. `string` is reference-typed
(it's a
dynamic array managed by GC in your case), so you can't check
it contents
in invariant. you CAN, however, use `f` methods in your
invariant, as `f`
is a struct which lives *inside* your object, and not a
reference var.
but note that it's a bad practice anyway, as some struct can
use some GC-
managed objects which can't be safely used in invariant block.
There are 2 problems here:
1. By definition, after the destructor is called the object state
is destroyed. It makes no sense to check the invariant after the
destructor is called because there is no state for us to check.
2. Invariants theoretically describe the legal states the object
can be in which includes variables that are GC managed, therefore
I should be able to check the invariant on GC managed objects as
well. What's the point of having this feature if I can't even
check the invariants of a simple data structure like a set, let
alone classes involving files?