using System; class A { ~A() { Console.WriteLine("Destruct instance of A"); } } class B { object Ref; public B(object o) { Ref = o; } ~B() { Console.WriteLine("Destruct instance of B"); } } class Test { static void Main() { B b = new B(new A()); b = null; GC.Collect(); GC.WaitForPendingFinalizers(); } }creates an instance of class A and an instance of class B. These objects become eligible for garbage collection when the variable b is assigned the value null, since after this time it is impossible for any user-written code to access them. The output could be either
Destruct instance of A Destruct instance of Bor
Destruct instance of B Destruct instance of Abecause the language imposes no constraints on the order in which objects are garbage collected. In subtle cases, the distinction between "eligible for destruction" and "eligible for collection" can be important. For example,
using System; class A { ~A() { Console.WriteLine("Destruct instance of A"); } public void F() { Console.WriteLine("A.F"); Test.RefA = this; } } class B { public A Ref; ~B() { Console.WriteLine("Destruct instance of B"); Ref.F(); } } class Test { public static A RefA; public static B RefB; static void Main() { RefB = new B(); RefA = new A(); RefB.Ref = RefA; RefB = null; RefA = null; // A and B now eligible for destruction GC.Collect(); GC.WaitForPendingFinalizers(); // B now eligible for collection, but A is not if (RefA != null) Console.WriteLine("RefA is not null"); } }In the above program, if the garbage collector chooses to run the destructor of A before the destructor of B, then the output of this program might be:
Destruct instance of A Destruct instance of B A.F RefA is not nullNote that although the instance of A was not in use and A's destructor was run, it is still possible for methods of A (in this case, F) to be called from another destructor. Also, note that running of a destructor may cause an object to become usable from the mainline program again. In this case, the running of B's destructor caused an instance of A that was previously not in use to become accessible from the live reference RefA. After the call to WaitForPendingFinalizers, the instance of B is eligible for collection, but the instance of A is not, because of the reference RefA. To avoid confusion and unexpected behavior, it is generally a good idea for destructors to only perform cleanup on data stored in their object's own fields, and not to perform any actions on referenced objects or static fields. end example]
| |
Jagger Software Ltd | |
Company # 4070126 | |
VAT # 762 5213 42 |