问题是如何测试调用 Finalize 时对象释放资源的事实。
该类的代码:
public class TestClass : IDisposable {
public bool HasBeenDisposed {get; private set; }
public void Dispose() {
HasBeenDisposed = true;
}
~TestClass() {
Dispose();
}
}
请注意我现在不关心 Dispose/Finalize 的正确实现,因为我想先找到测试它的方法。在这个阶段,假设已处置如果调用 Dispose/Finalize ware,则将设置为 true。
我写的实际测试如下:
更新为弱引用:
[Test]
public void IsCleanedUpOnGarbadgeCollection() {
var o = new TestClass();
o.HasBeenDisposed.Should().Be.False();
**var weak = new WeakReference(o, true); // true =Track after finalisation
o = null; // Make eligible for GC**
GC.Collect(0, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
**((TestClass)weak.Target)**.HasBeenDisposed.Should().Be.True();
}
或者我更喜欢的代码(更新后添加):
[Test]
public void IsCleanedUpOnGarbadgeCollection() {
WeakReference weak = null;
// Use action to isolate instance and make them eligible for GC
// Use WeakReference to track the object after finalisaiton
Action act = () = {
var o = new TestClass();
o.HasBeenDisposed.Should().Be.False();
weak = new WeakReference(o, true); // True=Track reference AFTER Finalize
};
act();
GC.Collect(0, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
// No access to o variable here which forces us to use WeakReference only to avoid error
((TestClass)weak.Target).HasBeenDisposed.Should().Be.True();
}
该测试失败(更新后通过)但我观察到以下(UPDATED):
- GC.WaitForPendingFinalizers() 确实挂起线程并最终确定实例o,但前提是没有扎根。为其分配 NULL 并使用 WeakReference 在最终确定后获取它。
- Finalize(析构函数)代码在正确的点执行o不持有实例。
那么测试这个的正确方法是什么。我想念什么?
我想这是变量o这会阻止 GC 收集它。
UPDATE: 是的,就是这个问题。不得不使用 WeakReference 来代替。