问题是如何测试对象在调用 finalize 时释放资源的事实。类的代码:
public class TestClass : IDisposable {
public bool HasBeenDisposed {get; private set; }
public void Dispose() {
HasBeenDisposed = true;
}
~TestClass() {
Dispose();
}
}
请注意,我现在并不关心 Dispose/Finalize 的正确实现,因为我想先找到测试它的方法。在这个阶段,假设如果调用 Dispose/Finalize 件, HasBeenDisposed将设置为 true 就足够了。
我写的实际测试看起来像:
UPDATED WITH WEAKREFERENCE:
[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();
}
该测试失败(PASSES AFTER UPDATE)但我观察到以下(更新):
- GC.WaitForPendingFinalizers() 确实挂起线程并最终确定o中的实例,但前提是没有植根。为其分配 NULL 并在最终确定后使用 WeakReference 获取它。
- 当o不保存实例时,在正确的点执行完成(析构函数)代码。
那么测试这个的正确方法是什么。我想念什么?
我想是变量o阻止了 GC 收集它。
更新:是的,这是问题所在。不得不改用弱引用。